summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/client/dbclient_cursor.cpp41
-rw-r--r--src/mongo/db/clientcursor.h4
-rw-r--r--src/mongo/db/commands/dbcommands_d.cpp8
-rw-r--r--src/mongo/db/commands/find_cmd.cpp119
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp2
-rw-r--r--src/mongo/db/commands/index_filter_commands.cpp13
-rw-r--r--src/mongo/db/commands/index_filter_commands_test.cpp36
-rw-r--r--src/mongo/db/commands/plan_cache_clear_command.cpp12
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp16
-rw-r--r--src/mongo/db/db_raii_test.cpp8
-rw-r--r--src/mongo/db/dbhelpers.cpp11
-rw-r--r--src/mongo/db/dbhelpers.h4
-rw-r--r--src/mongo/db/exec/idhack.cpp2
-rw-r--r--src/mongo/db/exec/sbe_cmd.cpp2
-rw-r--r--src/mongo/db/exec/subplan.cpp10
-rw-r--r--src/mongo/db/exec/trial_period_utils.cpp8
-rw-r--r--src/mongo/db/matcher/expression_optimize_test.cpp142
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp22
-rw-r--r--src/mongo/db/ops/parsed_update.cpp27
-rw-r--r--src/mongo/db/pipeline/aggregation_request_helper.cpp2
-rw-r--r--src/mongo/db/pipeline/aggregation_request_test.cpp6
-rw-r--r--src/mongo/db/pipeline/document_source_merge_cursors_test.cpp2
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp24
-rw-r--r--src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp3
-rw-r--r--src/mongo/db/pipeline/sharded_agg_helpers.cpp4
-rw-r--r--src/mongo/db/query/README.md6
-rw-r--r--src/mongo/db/query/SConscript2
-rw-r--r--src/mongo/db/query/canonical_query.cpp171
-rw-r--r--src/mongo/db/query/canonical_query.h41
-rw-r--r--src/mongo/db/query/canonical_query_encoder.cpp6
-rw-r--r--src/mongo/db/query/canonical_query_encoder_test.cpp13
-rw-r--r--src/mongo/db/query/canonical_query_test.cpp101
-rw-r--r--src/mongo/db/query/classic_stage_builder.cpp6
-rw-r--r--src/mongo/db/query/classic_stage_builder_test.cpp5
-rw-r--r--src/mongo/db/query/count_command_as_aggregation_command.cpp5
-rw-r--r--src/mongo/db/query/count_request.cpp2
-rw-r--r--src/mongo/db/query/find.cpp37
-rw-r--r--src/mongo/db/query/find_common.cpp12
-rw-r--r--src/mongo/db/query/find_common.h4
-rw-r--r--src/mongo/db/query/get_executor.cpp69
-rw-r--r--src/mongo/db/query/get_executor.h2
-rw-r--r--src/mongo/db/query/get_executor_test.cpp10
-rw-r--r--src/mongo/db/query/parsed_distinct.cpp54
-rw-r--r--src/mongo/db/query/plan_cache.cpp20
-rw-r--r--src/mongo/db/query/plan_cache_test.cpp107
-rw-r--r--src/mongo/db/query/plan_executor_impl.cpp2
-rw-r--r--src/mongo/db/query/plan_insert_listener.cpp2
-rw-r--r--src/mongo/db/query/planner_access.cpp14
-rw-r--r--src/mongo/db/query/planner_analysis.cpp45
-rw-r--r--src/mongo/db/query/query_planner.cpp25
-rw-r--r--src/mongo/db/query/query_planner_operator_test.cpp2
-rw-r--r--src/mongo/db/query/query_planner_options_test.cpp14
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.cpp60
-rw-r--r--src/mongo/db/query/query_request.h524
-rw-r--r--src/mongo/db/query/query_request_helper.cpp (renamed from src/mongo/db/query/query_request.cpp)726
-rw-r--r--src/mongo/db/query/query_request_helper.h166
-rw-r--r--src/mongo/db/query/query_request_test.cpp933
-rw-r--r--src/mongo/db/query/query_settings.cpp8
-rw-r--r--src/mongo/db/query/sbe_stage_builder.cpp2
-rw-r--r--src/mongo/db/query/sbe_stage_builder_test_fixture.cpp5
-rw-r--r--src/mongo/db/s/config/config_server_test_fixture.cpp2
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager.cpp19
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_create_database_test.cpp2
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_enable_sharding_test.cpp2
-rw-r--r--src/mongo/db/s/resharding/resharding_collection_cloner.cpp11
-rw-r--r--src/mongo/db/s/sharding_mongod_test_fixture.cpp2
-rw-r--r--src/mongo/db/service_entry_point_common.cpp6
-rw-r--r--src/mongo/db/transaction_history_iterator.cpp11
-rw-r--r--src/mongo/db/ttl.cpp6
-rw-r--r--src/mongo/db/update/update_driver.cpp7
-rw-r--r--src/mongo/dbtests/documentsourcetests.cpp36
-rw-r--r--src/mongo/dbtests/plan_executor_invalidation_test.cpp4
-rw-r--r--src/mongo/dbtests/plan_ranking.cpp94
-rw-r--r--src/mongo/dbtests/query_plan_executor.cpp12
-rw-r--r--src/mongo/dbtests/query_stage_cached_plan.cpp26
-rw-r--r--src/mongo/dbtests/query_stage_delete.cpp6
-rw-r--r--src/mongo/dbtests/query_stage_multiplan.cpp46
-rw-r--r--src/mongo/dbtests/query_stage_subplan.cpp62
-rw-r--r--src/mongo/dbtests/query_stage_update.cpp6
-rw-r--r--src/mongo/executor/remote_command_request.cpp6
-rw-r--r--src/mongo/s/balancer_configuration_test.cpp8
-rw-r--r--src/mongo/s/catalog/sharding_catalog_client_test.cpp62
-rw-r--r--src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp4
-rw-r--r--src/mongo/s/catalog_cache_refresh_test.cpp10
-rw-r--r--src/mongo/s/chunk_manager.cpp11
-rw-r--r--src/mongo/s/chunk_manager_index_bounds_test.cpp7
-rw-r--r--src/mongo/s/client/shard_remote.cpp23
-rw-r--r--src/mongo/s/cluster_identity_loader_test.cpp6
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.cpp72
-rw-r--r--src/mongo/s/commands/strategy.cpp54
-rw-r--r--src/mongo/s/commands/strategy.h6
-rw-r--r--src/mongo/s/query/async_results_merger_test.cpp2
-rw-r--r--src/mongo/s/query/cluster_find.cpp110
-rw-r--r--src/mongo/s/query/results_merger_test_fixture.h18
-rw-r--r--src/mongo/s/request_types/set_shard_version_request.cpp2
-rw-r--r--src/mongo/s/sessions_collection_sharded.cpp9
-rw-r--r--src/mongo/s/shard_key_pattern.cpp16
-rw-r--r--src/mongo/s/sharding_router_test_fixture.cpp6
-rw-r--r--src/mongo/s/write_ops/chunk_manager_targeter.cpp20
-rw-r--r--src/mongo/shell/bench.cpp81
100 files changed, 2152 insertions, 2470 deletions
diff --git a/src/mongo/client/dbclient_cursor.cpp b/src/mongo/client/dbclient_cursor.cpp
index 999a382b6ff..4dab6959f26 100644
--- a/src/mongo/client/dbclient_cursor.cpp
+++ b/src/mongo/client/dbclient_cursor.cpp
@@ -47,7 +47,7 @@
#include "mongo/db/pipeline/aggregation_request_helper.h"
#include "mongo/db/query/cursor_response.h"
#include "mongo/db/query/getmore_request.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/logv2/log.h"
#include "mongo/rpc/factory.h"
#include "mongo/rpc/get_status_from_command_result.h"
@@ -120,43 +120,46 @@ Message DBClientCursor::_assembleInit() {
} else if (_useFindCommand) {
// The caller supplies a 'query' object which may have $-prefixed directives in the format
// expected for a legacy OP_QUERY. Therefore, we use the legacy parsing code supplied by
- // QueryRequest. When actually issuing the request to the remote node, we will assemble a
- // find command.
- auto qr = QueryRequest::fromLegacyQuery(_nsOrUuid,
- query,
- fieldsToReturn ? *fieldsToReturn : BSONObj(),
- nToSkip,
- nextBatchSize(),
- opts);
- if (qr.isOK() && !qr.getValue()->isExplain()) {
+ // query_request_helper. When actually issuing the request to the remote node, we will
+ // assemble a find command.
+ bool explain = false;
+ auto findCommand =
+ query_request_helper::fromLegacyQuery(_nsOrUuid,
+ query,
+ fieldsToReturn ? *fieldsToReturn : BSONObj(),
+ nToSkip,
+ nextBatchSize(),
+ opts,
+ &explain);
+ if (findCommand.isOK() && !explain) {
if (query.getBoolField("$readOnce")) {
// Legacy queries don't handle readOnce.
- qr.getValue()->setReadOnce(true);
+ findCommand.getValue()->setReadOnce(true);
}
if (query.getBoolField(FindCommand::kRequestResumeTokenFieldName)) {
// Legacy queries don't handle requestResumeToken.
- qr.getValue()->setRequestResumeToken(true);
+ findCommand.getValue()->setRequestResumeToken(true);
}
if (query.hasField(FindCommand::kResumeAfterFieldName)) {
// Legacy queries don't handle resumeAfter.
- qr.getValue()->setResumeAfter(
+ findCommand.getValue()->setResumeAfter(
query.getObjectField(FindCommand::kResumeAfterFieldName));
}
if (auto replTerm = query[FindCommand::kTermFieldName]) {
// Legacy queries don't handle term.
- qr.getValue()->setReplicationTerm(replTerm.numberLong());
+ findCommand.getValue()->setTerm(replTerm.numberLong());
}
// Legacy queries don't handle readConcern.
// We prioritize the readConcern parsed from the query object over '_readConcernObj'.
if (auto readConcern = query[repl::ReadConcernArgs::kReadConcernFieldName]) {
- qr.getValue()->setReadConcern(readConcern.Obj());
+ findCommand.getValue()->setReadConcern(readConcern.Obj());
} else if (_readConcernObj) {
- qr.getValue()->setReadConcern(*_readConcernObj);
+ findCommand.getValue()->setReadConcern(_readConcernObj);
}
- BSONObj cmd = qr.getValue()->asFindCommand();
+ BSONObj cmd = findCommand.getValue()->toBSON(BSONObj());
if (auto readPref = query["$readPreference"]) {
- // QueryRequest doesn't handle $readPreference.
+ // FindCommand doesn't handle $readPreference.
cmd = BSONObjBuilder(std::move(cmd)).append(readPref).obj();
}
return assembleCommandRequest(_client, ns.db(), opts, std::move(cmd));
@@ -165,7 +168,7 @@ Message DBClientCursor::_assembleInit() {
// Legacy OP_QUERY request does not support UUIDs.
if (_nsOrUuid.uuid()) {
// If there was a problem building the query request, report that.
- uassertStatusOK(qr.getStatus());
+ uassertStatusOK(findCommand.getStatus());
// Otherwise it must have been explain.
uasserted(50937, "Query by UUID is not supported for explain queries.");
}
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index 745b03157f3..4e6137751f0 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -68,9 +68,7 @@ struct ClientCursorParams {
apiParameters(std::move(apiParameters)),
writeConcernOptions(std::move(writeConcernOptions)),
readConcernArgs(std::move(readConcernArgs)),
- queryOptions(exec->getCanonicalQuery()
- ? exec->getCanonicalQuery()->getQueryRequest().getOptions()
- : 0),
+ queryOptions(exec->getCanonicalQuery() ? exec->getCanonicalQuery()->getOptions() : 0),
originatingCommandObj(originatingCommandObj.getOwned()),
originatingPrivileges(std::move(originatingPrivileges)) {
while (authenticatedUsersIter.more()) {
diff --git a/src/mongo/db/commands/dbcommands_d.cpp b/src/mongo/db/commands/dbcommands_d.cpp
index 66b175fd6bb..6ec683052f9 100644
--- a/src/mongo/db/commands/dbcommands_d.cpp
+++ b/src/mongo/db/commands/dbcommands_d.cpp
@@ -289,11 +289,11 @@ public:
BSONObj sort = BSON("files_id" << 1 << "n" << 1);
return writeConflictRetry(opCtx, "filemd5", dbname, [&] {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query.getOwned());
+ findCommand->setSort(sort.getOwned());
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
if (!statusWithCQ.isOK()) {
uasserted(17240, "Can't canonicalize query " + query.toString());
return false;
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 2b7665c8638..e315f1c314f 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -65,31 +65,29 @@ namespace {
const auto kTermField = "term"_sd;
-// Parses the command object to a QueryRequest. If the client request did not specify any runtime
+// Parses the command object to a FindCommand. If the client request did not specify any runtime
// constants, make them available to the query here.
-std::unique_ptr<QueryRequest> parseCmdObjectToQueryRequest(OperationContext* opCtx,
- NamespaceString nss,
- BSONObj cmdObj,
- bool isExplain) {
- auto qr =
- QueryRequest::makeFromFindCommand(std::move(cmdObj),
- isExplain,
- std::move(nss),
- APIParameters::get(opCtx).getAPIStrict().value_or(false));
- if (!qr->getLegacyRuntimeConstants()) {
- qr->setLegacyRuntimeConstants(Variables::generateRuntimeConstants(opCtx));
+std::unique_ptr<FindCommand> parseCmdObjectToFindCommand(OperationContext* opCtx,
+ NamespaceString nss,
+ BSONObj cmdObj) {
+ auto findCommand = query_request_helper::makeFromFindCommand(
+ std::move(cmdObj),
+ std::move(nss),
+ APIParameters::get(opCtx).getAPIStrict().value_or(false));
+ if (!findCommand->getLegacyRuntimeConstants()) {
+ findCommand->setLegacyRuntimeConstants(Variables::generateRuntimeConstants(opCtx));
}
- return qr;
+ return findCommand;
}
boost::intrusive_ptr<ExpressionContext> makeExpressionContext(
OperationContext* opCtx,
- const QueryRequest& queryRequest,
+ const FindCommand& findCommand,
boost::optional<ExplainOptions::Verbosity> verbosity) {
std::unique_ptr<CollatorInterface> collator;
- if (!queryRequest.getCollation().isEmpty()) {
+ if (!findCommand.getCollation().isEmpty()) {
collator = uassertStatusOK(CollatorFactoryInterface::get(opCtx->getServiceContext())
- ->makeFromBSON(queryRequest.getCollation()));
+ ->makeFromBSON(findCommand.getCollation()));
}
// Although both 'find' and 'aggregate' commands have an ExpressionContext, some of the data
@@ -106,23 +104,23 @@ boost::intrusive_ptr<ExpressionContext> makeExpressionContext(
//
// As we change the code to make the find and agg systems more tightly coupled, it would make
// sense to start initializing these fields for find operations as well.
- auto expCtx =
- make_intrusive<ExpressionContext>(opCtx,
- verbosity,
- false, // fromMongos
- false, // needsMerge
- queryRequest.allowDiskUse(),
- false, // bypassDocumentValidation
- false, // isMapReduceCommand
- queryRequest.nss(),
- queryRequest.getLegacyRuntimeConstants(),
- std::move(collator),
- nullptr, // mongoProcessInterface
- StringMap<ExpressionContext::ResolvedNamespace>{},
- boost::none, // uuid
- queryRequest.getLetParameters(), // let
- CurOp::get(opCtx)->dbProfileLevel() > 0 // mayDbProfile
- );
+ auto expCtx = make_intrusive<ExpressionContext>(
+ opCtx,
+ verbosity,
+ false, // fromMongos
+ false, // needsMerge
+ findCommand.getAllowDiskUse(),
+ false, // bypassDocumentValidation
+ false, // isMapReduceCommand
+ findCommand.getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ findCommand.getLegacyRuntimeConstants(),
+ std::move(collator),
+ nullptr, // mongoProcessInterface
+ StringMap<ExpressionContext::ResolvedNamespace>{},
+ boost::none, // uuid
+ findCommand.getLet(), // let
+ CurOp::get(opCtx)->dbProfileLevel() > 0 // mayDbProfile
+ );
expCtx->tempDir = storageGlobalParams.dbpath + "/_tmp";
return expCtx;
}
@@ -250,16 +248,17 @@ public:
AutoGetCollectionViewMode::kViewsPermitted);
const auto nss = ctx->getNss();
- // Parse the command BSON to a QueryRequest.
- const bool isExplain = true;
- auto qr = parseCmdObjectToQueryRequest(opCtx, nss, _request.body, isExplain);
+ // Parse the command BSON to a FindCommand.
+ auto findCommand = parseCmdObjectToFindCommand(opCtx, nss, _request.body);
- // Finish the parsing step by using the QueryRequest to create a CanonicalQuery.
+ // Finish the parsing step by using the FindCommand to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *qr, verbosity);
+ auto expCtx = makeExpressionContext(opCtx, *findCommand, verbosity);
+ const bool isExplain = true;
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
std::move(expCtx),
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures));
@@ -270,8 +269,9 @@ public:
// Convert the find command into an aggregation using $match (and other stages, as
// necessary), if possible.
- const auto& qr = cq->getQueryRequest();
- auto viewAggregationCommand = uassertStatusOK(qr.asAggregationCommand());
+ const auto& findCommand = cq->getFindCommand();
+ auto viewAggregationCommand =
+ uassertStatusOK(query_request_helper::asAggregationCommand(findCommand));
auto viewAggCmd = OpMsgRequest::fromDBAndBody(_dbName, viewAggregationCommand).body;
// Create the agg request equivalent of the find operation, with the explain
@@ -329,31 +329,32 @@ public:
const BSONObj& cmdObj = _request.body;
- // Parse the command BSON to a QueryRequest. Pass in the parsedNss in case cmdObj does
+ // Parse the command BSON to a FindCommand. Pass in the parsedNss in case cmdObj does
// not have a UUID.
auto parsedNss = NamespaceString{CommandHelpers::parseNsFromCommand(_dbName, cmdObj)};
const bool isExplain = false;
const bool isOplogNss = (parsedNss == NamespaceString::kRsOplogNamespace);
- auto qr = parseCmdObjectToQueryRequest(opCtx, std::move(parsedNss), cmdObj, isExplain);
+ auto findCommand = parseCmdObjectToFindCommand(opCtx, std::move(parsedNss), cmdObj);
// Only allow speculative majority for internal commands that specify the correct flag.
uassert(ErrorCodes::ReadConcernMajorityNotEnabled,
"Majority read concern is not enabled.",
!(repl::ReadConcernArgs::get(opCtx).isSpeculativeMajority() &&
- !qr->allowSpeculativeMajorityRead()));
+ !findCommand->getAllowSpeculativeMajorityRead()));
auto replCoord = repl::ReplicationCoordinator::get(opCtx);
const auto txnParticipant = TransactionParticipant::get(opCtx);
uassert(ErrorCodes::InvalidOptions,
"It is illegal to open a tailable cursor in a transaction",
- !(opCtx->inMultiDocumentTransaction() && qr->isTailable()));
+ !(opCtx->inMultiDocumentTransaction() && findCommand->getTailable()));
uassert(ErrorCodes::OperationNotSupportedInTransaction,
"The 'readOnce' option is not supported within a transaction.",
- !txnParticipant || !opCtx->inMultiDocumentTransaction() || !qr->isReadOnce());
+ !txnParticipant || !opCtx->inMultiDocumentTransaction() ||
+ !findCommand->getReadOnce());
// Validate term before acquiring locks, if provided.
- auto term = qr->getReplicationTerm();
+ auto term = findCommand->getTerm();
if (term) {
// Note: updateTerm returns ok if term stayed the same.
uassertStatusOK(replCoord->updateTerm(opCtx, *term));
@@ -379,13 +380,13 @@ public:
const auto& nss = ctx->getNss();
uassert(ErrorCodes::NamespaceNotFound,
- str::stream() << "UUID " << qr->uuid().get()
+ str::stream() << "UUID " << findCommand->getNamespaceOrUUID().uuid().get()
<< " specified in query request not found",
- ctx || !qr->uuid());
+ ctx || !findCommand->getNamespaceOrUUID().uuid());
// Set the namespace if a collection was found, as opposed to nothing or a view.
if (ctx) {
- qr->refreshNSS(ctx->getNss());
+ query_request_helper::refreshNSS(ctx->getNss(), findCommand.get());
}
// Check whether we are allowed to read from this node after acquiring our locks.
@@ -401,12 +402,13 @@ public:
const int ntoskip = -1;
beginQueryOp(opCtx, nss, _request.body, ntoreturn, ntoskip);
- // Finish the parsing step by using the QueryRequest to create a CanonicalQuery.
+ // Finish the parsing step by using the FindCommand to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *qr, boost::none /* verbosity */);
+ auto expCtx = makeExpressionContext(opCtx, *findCommand, boost::none /* verbosity */);
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
std::move(expCtx),
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures));
@@ -417,8 +419,9 @@ public:
// Convert the find command into an aggregation using $match (and other stages, as
// necessary), if possible.
- const auto& qr = cq->getQueryRequest();
- auto viewAggregationCommand = uassertStatusOK(qr.asAggregationCommand());
+ const auto& findCommand = cq->getFindCommand();
+ auto viewAggregationCommand =
+ uassertStatusOK(query_request_helper::asAggregationCommand(findCommand));
BSONObj aggResult = CommandHelpers::runCommandDirectly(
opCtx, OpMsgRequest::fromDBAndBody(_dbName, std::move(viewAggregationCommand)));
@@ -434,7 +437,7 @@ public:
const auto& collection = ctx->getCollection();
- if (cq->getQueryRequest().isReadOnce()) {
+ if (cq->getFindCommand().getReadOnce()) {
// The readOnce option causes any storage-layer cursors created during plan
// execution to assume read data will not be needed again and need not be cached.
opCtx->recoveryUnit()->setReadOnce(true);
@@ -463,7 +466,7 @@ public:
FindCommon::waitInFindBeforeMakingBatch(opCtx, *exec->getCanonicalQuery());
- const QueryRequest& originalQR = exec->getCanonicalQuery()->getQueryRequest();
+ const FindCommand& originalFC = exec->getCanonicalQuery()->getFindCommand();
// Stream query results, adding them to a BSONArray as we go.
CursorResponseBuilder::Options options;
@@ -479,7 +482,7 @@ public:
ResourceConsumption::DocumentUnitCounter docUnitsReturned;
try {
- while (!FindCommon::enoughForFirstBatch(originalQR, numResults) &&
+ while (!FindCommon::enoughForFirstBatch(originalFC, numResults) &&
PlanExecutor::ADVANCED == (state = exec->getNext(&obj, nullptr))) {
// If we can't fit this result inside the current batch, then we stash it for
// later.
diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp
index 50c742a612d..50242d38565 100644
--- a/src/mongo/db/commands/getmore_cmd.cpp
+++ b/src/mongo/db/commands/getmore_cmd.cpp
@@ -521,7 +521,7 @@ public:
PlanExecutor* exec = cursorPin->getExecutor();
const auto* cq = exec->getCanonicalQuery();
- if (cq && cq->getQueryRequest().isReadOnce()) {
+ if (cq && cq->getFindCommand().getReadOnce()) {
// The readOnce option causes any storage-layer cursors created during plan
// execution to assume read data will not be needed again and need not be cached.
opCtx->recoveryUnit()->setReadOnce(true);
diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp
index c9a82127980..286b3595056 100644
--- a/src/mongo/db/commands/index_filter_commands.cpp
+++ b/src/mongo/db/commands/index_filter_commands.cpp
@@ -303,15 +303,16 @@ Status ClearFilters::clear(OperationContext* opCtx,
AllowedIndexEntry entry = *i;
// Create canonical query.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(entry.query);
- qr->setSort(entry.sort);
- qr->setProj(entry.projection);
- qr->setCollation(entry.collation);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(entry.query);
+ findCommand->setSort(entry.sort);
+ findCommand->setProjection(entry.projection);
+ findCommand->setCollation(entry.collation);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp
index b1b7e7b7e29..760ccfbf9d2 100644
--- a/src/mongo/db/commands/index_filter_commands_test.cpp
+++ b/src/mongo/db/commands/index_filter_commands_test.cpp
@@ -130,12 +130,12 @@ void addQueryShapeToPlanCache(OperationContext* opCtx,
const char* projectionStr,
const char* collationStr) {
// Create canonical query.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projectionStr));
- qr->setCollation(fromjson(collationStr));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projectionStr));
+ findCommand->setCollation(fromjson(collationStr));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -161,12 +161,12 @@ bool planCacheContains(OperationContext* opCtx,
const char* collationStr) {
// Create canonical query.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projectionStr));
- qr->setCollation(fromjson(collationStr));
- auto statusWithInputQuery = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projectionStr));
+ findCommand->setCollation(fromjson(collationStr));
+ auto statusWithInputQuery = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
ASSERT_OK(statusWithInputQuery.getStatus());
unique_ptr<CanonicalQuery> inputQuery = std::move(statusWithInputQuery.getValue());
@@ -181,12 +181,12 @@ bool planCacheContains(OperationContext* opCtx,
// Canonicalize the query shape stored in the cache entry in order to get the plan cache
// key.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(createdFromQuery.filter);
- qr->setSort(createdFromQuery.sort);
- qr->setProj(createdFromQuery.projection);
- qr->setCollation(createdFromQuery.collation);
- auto statusWithCurrentQuery = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(createdFromQuery.filter);
+ findCommand->setSort(createdFromQuery.sort);
+ findCommand->setProjection(createdFromQuery.projection);
+ findCommand->setCollation(createdFromQuery.collation);
+ auto statusWithCurrentQuery = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
ASSERT_OK(statusWithCurrentQuery.getStatus());
unique_ptr<CanonicalQuery> currentQuery = std::move(statusWithCurrentQuery.getValue());
diff --git a/src/mongo/db/commands/plan_cache_clear_command.cpp b/src/mongo/db/commands/plan_cache_clear_command.cpp
index 5dc3822bd4a..69c632bdc0a 100644
--- a/src/mongo/db/commands/plan_cache_clear_command.cpp
+++ b/src/mongo/db/commands/plan_cache_clear_command.cpp
@@ -86,9 +86,9 @@ Status clear(OperationContext* opCtx,
"Query shape doesn't exist in PlanCache",
"namespace"_attr = ns,
"query"_attr = redact(cq->getQueryObj()),
- "sort"_attr = cq->getQueryRequest().getSort(),
- "projection"_attr = cq->getQueryRequest().getProj(),
- "collation"_attr = cq->getQueryRequest().getCollation());
+ "sort"_attr = cq->getFindCommand().getSort(),
+ "projection"_attr = cq->getFindCommand().getProjection(),
+ "collation"_attr = cq->getFindCommand().getCollation());
return Status::OK();
}
@@ -99,9 +99,9 @@ Status clear(OperationContext* opCtx,
"Removed plan cache entry",
"namespace"_attr = ns,
"query"_attr = redact(cq->getQueryObj()),
- "sort"_attr = cq->getQueryRequest().getSort(),
- "projection"_attr = cq->getQueryRequest().getProj(),
- "collation"_attr = cq->getQueryRequest().getCollation());
+ "sort"_attr = cq->getFindCommand().getSort(),
+ "projection"_attr = cq->getFindCommand().getProjection(),
+ "collation"_attr = cq->getFindCommand().getCollation());
return Status::OK();
}
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index 443d3ecc4dc..7ac23d5911b 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -85,16 +85,18 @@ StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(OperationContext* opCtx
}
// Create canonical query
- auto qr = std::make_unique<QueryRequest>(NamespaceString{ns});
- qr->setFilter(queryObj);
- qr->setSort(sortObj);
- qr->setProj(projObj);
- qr->setCollation(collationObj);
- const ExtensionsCallbackReal extensionsCallback(opCtx, &qr->nss());
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString{ns});
+ findCommand->setFilter(queryObj.getOwned());
+ findCommand->setSort(sortObj.getOwned());
+ findCommand->setProjection(projObj.getOwned());
+ findCommand->setCollation(collationObj.getOwned());
+ const ExtensionsCallbackReal extensionsCallback(
+ opCtx, findCommand->getNamespaceOrUUID().nss().get_ptr());
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/db_raii_test.cpp b/src/mongo/db/db_raii_test.cpp
index 72a9fab784b..cf142ce0222 100644
--- a/src/mongo/db/db_raii_test.cpp
+++ b/src/mongo/db/db_raii_test.cpp
@@ -70,8 +70,9 @@ public:
std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> makeTailableQueryPlan(
OperationContext* opCtx, const CollectionPtr& collection) {
- auto qr = std::make_unique<QueryRequest>(collection->ns());
- qr->setTailableMode(TailableModeEnum::kTailableAndAwaitData);
+ auto findCommand = std::make_unique<FindCommand>(collection->ns());
+ query_request_helper::setTailableMode(TailableModeEnum::kTailableAndAwaitData,
+ findCommand.get());
awaitDataState(opCtx).shouldWaitForInserts = true;
awaitDataState(opCtx).waitForInsertsDeadline =
@@ -81,7 +82,8 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> makeTailableQueryPlan(
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ = CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kBanAllSpecialFeatures);
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index 94d5ef3e3d3..3fc790e9bec 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -81,14 +81,14 @@ RecordId Helpers::findOne(OperationContext* opCtx,
if (!collection)
return RecordId();
- auto qr = std::make_unique<QueryRequest>(collection->ns());
- qr->setFilter(query);
- return findOne(opCtx, collection, std::move(qr), requireIndex);
+ auto findCommand = std::make_unique<FindCommand>(collection->ns());
+ findCommand->setFilter(query);
+ return findOne(opCtx, collection, std::move(findCommand), requireIndex);
}
RecordId Helpers::findOne(OperationContext* opCtx,
const CollectionPtr& collection,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
bool requireIndex) {
if (!collection)
return RecordId();
@@ -98,7 +98,8 @@ RecordId Helpers::findOne(OperationContext* opCtx,
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h
index 54fe7635ce4..284e1b4d051 100644
--- a/src/mongo/db/dbhelpers.h
+++ b/src/mongo/db/dbhelpers.h
@@ -39,7 +39,7 @@ class Collection;
class CollectionPtr;
class Database;
class OperationContext;
-class QueryRequest;
+class FindCommand;
/**
* db helpers are helper functions and classes that let us easily manipulate the local
@@ -75,7 +75,7 @@ struct Helpers {
bool requireIndex);
static RecordId findOne(OperationContext* opCtx,
const CollectionPtr& collection,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> qr,
bool requireIndex);
/**
diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp
index af8edac2a9b..db3a668bf27 100644
--- a/src/mongo/db/exec/idhack.cpp
+++ b/src/mongo/db/exec/idhack.cpp
@@ -58,7 +58,7 @@ IDHackStage::IDHackStage(ExpressionContext* expCtx,
_workingSet(ws),
_key(query->getQueryObj()["_id"].wrap()) {
_specificStats.indexName = descriptor->indexName();
- _addKeyMetadata = query->getQueryRequest().returnKey();
+ _addKeyMetadata = query->getFindCommand().getReturnKey();
}
IDHackStage::IDHackStage(ExpressionContext* expCtx,
diff --git a/src/mongo/db/exec/sbe_cmd.cpp b/src/mongo/db/exec/sbe_cmd.cpp
index 680a5ae60f8..41451657e87 100644
--- a/src/mongo/db/exec/sbe_cmd.cpp
+++ b/src/mongo/db/exec/sbe_cmd.cpp
@@ -67,7 +67,7 @@ public:
CommandHelpers::handleMarkKillOnClientDisconnect(opCtx);
long long batchSize;
uassertStatusOK(CursorRequest::parseCommandCursorOptions(
- cmdObj, QueryRequest::kDefaultBatchSize, &batchSize));
+ cmdObj, query_request_helper::kDefaultBatchSize, &batchSize));
sbe::Parser parser;
auto root = parser.parse(opCtx, dbname, cmdObj["sbe"].String());
diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp
index c97c85d361e..9aaea0bb41d 100644
--- a/src/mongo/db/exec/subplan.cpp
+++ b/src/mongo/db/exec/subplan.cpp
@@ -72,28 +72,28 @@ SubplanStage::SubplanStage(ExpressionContext* expCtx,
}
bool SubplanStage::canUseSubplanning(const CanonicalQuery& query) {
- const QueryRequest& qr = query.getQueryRequest();
+ const FindCommand& findCommand = query.getFindCommand();
const MatchExpression* expr = query.root();
// Hint provided
- if (!qr.getHint().isEmpty()) {
+ if (!findCommand.getHint().isEmpty()) {
return false;
}
// Min provided
// Min queries are a special case of hinted queries.
- if (!qr.getMin().isEmpty()) {
+ if (!findCommand.getMin().isEmpty()) {
return false;
}
// Max provided
// Similar to min, max queries are a special case of hinted queries.
- if (!qr.getMax().isEmpty()) {
+ if (!findCommand.getMax().isEmpty()) {
return false;
}
// Tailable cursors won't get cached, just turn into collscans.
- if (query.getQueryRequest().isTailable()) {
+ if (findCommand.getTailable()) {
return false;
}
diff --git a/src/mongo/db/exec/trial_period_utils.cpp b/src/mongo/db/exec/trial_period_utils.cpp
index 4369ff40a08..9a7bbe8bc41 100644
--- a/src/mongo/db/exec/trial_period_utils.cpp
+++ b/src/mongo/db/exec/trial_period_utils.cpp
@@ -54,11 +54,11 @@ size_t getTrialPeriodNumToReturn(const CanonicalQuery& query) {
// Determine the number of results which we will produce during the plan ranking phase before
// stopping.
size_t numResults = static_cast<size_t>(internalQueryPlanEvaluationMaxResults.load());
- if (query.getQueryRequest().getNToReturn()) {
+ if (query.getFindCommand().getNtoreturn()) {
numResults =
- std::min(static_cast<size_t>(*query.getQueryRequest().getNToReturn()), numResults);
- } else if (query.getQueryRequest().getLimit()) {
- numResults = std::min(static_cast<size_t>(*query.getQueryRequest().getLimit()), numResults);
+ std::min(static_cast<size_t>(*query.getFindCommand().getNtoreturn()), numResults);
+ } else if (query.getFindCommand().getLimit()) {
+ numResults = std::min(static_cast<size_t>(*query.getFindCommand().getLimit()), numResults);
}
return numResults;
diff --git a/src/mongo/db/matcher/expression_optimize_test.cpp b/src/mongo/db/matcher/expression_optimize_test.cpp
index e46b9aaddba..2141c210a35 100644
--- a/src/mongo/db/matcher/expression_optimize_test.cpp
+++ b/src/mongo/db/matcher/expression_optimize_test.cpp
@@ -69,20 +69,20 @@ MatchExpression* parseMatchExpression(const BSONObj& obj) {
* (expression tree, query request) tuple passes CanonicalQuery::isValid().
* Returns Status::OK() if the tuple is valid, else returns an error Status.
*/
-Status isValid(const std::string& queryStr, const QueryRequest& qrRaw) {
+Status isValid(const std::string& queryStr, const FindCommand& findCommand) {
BSONObj queryObj = fromjson(queryStr);
std::unique_ptr<MatchExpression> me(parseMatchExpression(queryObj));
me = MatchExpression::optimize(std::move(me));
- return CanonicalQuery::isValid(me.get(), qrRaw).getStatus();
+ return CanonicalQuery::isValid(me.get(), findCommand).getStatus();
}
TEST(ExpressionOptimizeTest, IsValidText) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Valid: regular TEXT.
- ASSERT_OK(isValid("{$text: {$search: 's'}}", *qr));
+ ASSERT_OK(isValid("{$text: {$search: 's'}}", *findCommand));
// Valid: TEXT inside OR.
ASSERT_OK(
@@ -90,13 +90,13 @@ TEST(ExpressionOptimizeTest, IsValidText) {
" {$text: {$search: 's'}},"
" {a: 1}"
"]}",
- *qr));
+ *findCommand));
// Valid: TEXT outside NOR.
- ASSERT_OK(isValid("{$text: {$search: 's'}, $nor: [{a: 1}, {b: 1}]}", *qr));
+ ASSERT_OK(isValid("{$text: {$search: 's'}, $nor: [{a: 1}, {b: 1}]}", *findCommand));
// Invalid: TEXT inside NOR.
- ASSERT_NOT_OK(isValid("{$nor: [{$text: {$search: 's'}}, {a: 1}]}", *qr));
+ ASSERT_NOT_OK(isValid("{$nor: [{$text: {$search: 's'}}, {a: 1}]}", *findCommand));
// Invalid: TEXT inside NOR.
ASSERT_NOT_OK(
@@ -107,7 +107,7 @@ TEST(ExpressionOptimizeTest, IsValidText) {
" ]},"
" {a: 2}"
"]}",
- *qr));
+ *findCommand));
// Invalid: >1 TEXT.
ASSERT_NOT_OK(
@@ -115,7 +115,7 @@ TEST(ExpressionOptimizeTest, IsValidText) {
" {$text: {$search: 's'}},"
" {$text: {$search: 't'}}"
"]}",
- *qr));
+ *findCommand));
// Invalid: >1 TEXT.
ASSERT_NOT_OK(
@@ -129,26 +129,26 @@ TEST(ExpressionOptimizeTest, IsValidText) {
" {b: 1}"
" ]}"
"]}",
- *qr));
+ *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidTextTailable) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setTailableMode(TailableModeEnum::kTailable);
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ query_request_helper::setTailableMode(TailableModeEnum::kTailable, findCommand.get());
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: TEXT and tailable.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidGeo) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Valid: regular GEO_NEAR.
- ASSERT_OK(isValid("{a: {$near: [0, 0]}}", *qr));
+ ASSERT_OK(isValid("{a: {$near: [0, 0]}}", *findCommand));
// Valid: GEO_NEAR inside nested AND.
ASSERT_OK(
@@ -159,7 +159,7 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" ]},"
" {c: 1}"
"]}",
- *qr));
+ *findCommand));
// Invalid: >1 GEO_NEAR.
ASSERT_NOT_OK(
@@ -167,7 +167,7 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" {a: {$near: [0, 0]}},"
" {b: {$near: [0, 0]}}"
"]}",
- *qr));
+ *findCommand));
// Invalid: >1 GEO_NEAR.
ASSERT_NOT_OK(
@@ -175,7 +175,7 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" {a: {$geoNear: [0, 0]}},"
" {b: {$near: [0, 0]}}"
"]}",
- *qr));
+ *findCommand));
// Invalid: >1 GEO_NEAR.
ASSERT_NOT_OK(
@@ -189,7 +189,7 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" {d: 1}"
" ]}"
"]}",
- *qr));
+ *findCommand));
// Invalid: GEO_NEAR inside NOR.
ASSERT_NOT_OK(
@@ -197,7 +197,7 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" {a: {$near: [0, 0]}},"
" {b: 1}"
"]}",
- *qr));
+ *findCommand));
// Invalid: GEO_NEAR inside OR.
ASSERT_NOT_OK(
@@ -205,19 +205,19 @@ TEST(ExpressionOptimizeTest, IsValidGeo) {
" {a: {$near: [0, 0]}},"
" {b: 1}"
"]}",
- *qr));
+ *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidTextAndGeo) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: TEXT and GEO_NEAR.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}, a: {$near: [0, 0]}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}, a: {$near: [0, 0]}}", *findCommand));
// Invalid: TEXT and GEO_NEAR.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}, a: {$geoNear: [0, 0]}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}, a: {$geoNear: [0, 0]}}", *findCommand));
// Invalid: TEXT and GEO_NEAR.
ASSERT_NOT_OK(
@@ -226,89 +226,85 @@ TEST(ExpressionOptimizeTest, IsValidTextAndGeo) {
" {a: 1}"
" ],"
" b: {$near: [0, 0]}}",
- *qr));
+ *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidTextAndNaturalAscending) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setSort(fromjson("{$natural: 1}"));
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setSort(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: TEXT and {$natural: 1} sort order.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidTextAndNaturalDescending) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setSort(fromjson("{$natural: -1}"));
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setSort(fromjson("{$natural: -1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: TEXT and {$natural: -1} sort order.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidTextAndHint) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setHint(fromjson("{a: 1}"));
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setHint(fromjson("{a: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: TEXT and {$natural: -1} sort order.
- ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *qr));
+ ASSERT_NOT_OK(isValid("{$text: {$search: 's'}}", *findCommand));
}
// SERVER-14366
TEST(ExpressionOptimizeTest, IsValidGeoNearNaturalSort) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setSort(fromjson("{$natural: 1}"));
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setSort(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: GEO_NEAR and {$natural: 1} sort order.
- ASSERT_NOT_OK(isValid("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}", *qr));
+ ASSERT_NOT_OK(
+ isValid("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}", *findCommand));
}
// SERVER-14366
TEST(ExpressionOptimizeTest, IsValidGeoNearNaturalHint) {
- // Filter inside QueryRequest is not used.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setHint(fromjson("{$natural: 1}"));
- ASSERT_OK(qr->validate());
+ // Filter inside FindCommand is not used.
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setHint(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(*findCommand));
// Invalid: GEO_NEAR and {$natural: 1} hint.
- ASSERT_NOT_OK(isValid("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}", *qr));
+ ASSERT_NOT_OK(
+ isValid("{a: {$near: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidNaturalSortIndexHint) {
- const bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(
- fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {a: 1}, '$db': 'test'}"),
- isExplain);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(
+ fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {a: 1}, '$db': 'test'}"));
// Invalid: {$natural: 1} sort order and index hint.
- ASSERT_NOT_OK(isValid("{}", *qr));
+ ASSERT_NOT_OK(isValid("{}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidNaturalSortNaturalHint) {
- const bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(
- fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {$natural: 1}, '$db': 'test'}"),
- isExplain);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(
+ fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {$natural: 1}, '$db': 'test'}"));
// Valid: {$natural: 1} sort order and {$natural: 1} hint.
- ASSERT_OK(isValid("{}", *qr));
+ ASSERT_OK(isValid("{}", *findCommand));
}
TEST(ExpressionOptimizeTest, IsValidNaturalSortNaturalHintDifferentDirections) {
- const bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(
- fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {$natural: -1}, '$db': 'test'}"),
- isExplain);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(
+ fromjson("{find: 'testcoll', sort: {$natural: 1}, hint: {$natural: -1}, '$db': 'test'}"));
// Invalid: {$natural: 1} sort order and {$natural: -1} hint.
- ASSERT_NOT_OK(isValid("{}", *qr));
+ ASSERT_NOT_OK(isValid("{}", *findCommand));
}
TEST(ExpressionOptimizeTest, NormalizeWithInPreservesTags) {
diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp
index e2bc0f0432f..0837f51addc 100644
--- a/src/mongo/db/ops/parsed_delete.cpp
+++ b/src/mongo/db/ops/parsed_delete.cpp
@@ -90,12 +90,11 @@ Status ParsedDelete::parseQueryToCQ() {
// The projection needs to be applied after the delete operation, so we do not specify a
// projection during canonicalization.
- auto qr = std::make_unique<QueryRequest>(_request->getNsString());
- qr->setFilter(_request->getQuery());
- qr->setSort(_request->getSort());
- qr->setCollation(_request->getCollation());
- qr->setExplain(_request->getIsExplain());
- qr->setHint(_request->getHint());
+ auto findCommand = std::make_unique<FindCommand>(_request->getNsString());
+ findCommand->setFilter(_request->getQuery().getOwned());
+ findCommand->setSort(_request->getSort().getOwned());
+ findCommand->setCollation(_request->getCollation().getOwned());
+ findCommand->setHint(_request->getHint());
// 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
@@ -104,19 +103,20 @@ Status ParsedDelete::parseQueryToCQ() {
// has not actually deleted a document. This behavior is fine for findAndModify, but should
// not apply to deletes in general.
if (!_request->getMulti() && !_request->getSort().isEmpty()) {
- qr->setLimit(1);
+ findCommand->setLimit(1);
}
// If the delete request has runtime constants or let parameters attached to it, pass them to
- // the QueryRequest.
+ // the FindCommand.
if (auto& runtimeConstants = _request->getLegacyRuntimeConstants())
- qr->setLegacyRuntimeConstants(*runtimeConstants);
+ findCommand->setLegacyRuntimeConstants(*runtimeConstants);
if (auto& letParams = _request->getLet())
- qr->setLetParameters(*letParams);
+ findCommand->setLet(*letParams);
auto statusWithCQ =
CanonicalQuery::canonicalize(_opCtx,
- std::move(qr),
+ std::move(findCommand),
+ _request->getIsExplain(),
_expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp
index c21933d9876..fbdc4e0a43e 100644
--- a/src/mongo/db/ops/parsed_update.cpp
+++ b/src/mongo/db/ops/parsed_update.cpp
@@ -122,15 +122,14 @@ Status ParsedUpdate::parseQueryToCQ() {
// The projection needs to be applied after the update operation, so we do not specify a
// projection during canonicalization.
- auto qr = std::make_unique<QueryRequest>(_request->getNamespaceString());
- qr->setFilter(_request->getQuery());
- qr->setSort(_request->getSort());
- qr->setExplain(static_cast<bool>(_request->explain()));
- qr->setHint(_request->getHint());
+ auto findCommand = std::make_unique<FindCommand>(_request->getNamespaceString());
+ findCommand->setFilter(_request->getQuery());
+ findCommand->setSort(_request->getSort());
+ findCommand->setHint(_request->getHint());
// We get the collation off the ExpressionContext because it may contain a collection-default
// collator if no collation was included in the user's request.
- qr->setCollation(_expCtx->getCollatorBSON());
+ findCommand->setCollation(_expCtx->getCollatorBSON());
// 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
@@ -139,7 +138,7 @@ Status ParsedUpdate::parseQueryToCQ() {
// 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);
+ findCommand->setLimit(1);
}
// $expr is not allowed in the query for an upsert, since it is not clear what the equality
@@ -151,16 +150,20 @@ Status ParsedUpdate::parseQueryToCQ() {
}
// If the update request has runtime constants or let parameters attached to it, pass them to
- // the QueryRequest.
+ // the FindCommand.
if (auto& runtimeConstants = _request->getLegacyRuntimeConstants()) {
- qr->setLegacyRuntimeConstants(*runtimeConstants);
+ findCommand->setLegacyRuntimeConstants(*runtimeConstants);
}
if (auto& letParams = _request->getLetParameters()) {
- qr->setLetParameters(*letParams);
+ findCommand->setLet(*letParams);
}
- auto statusWithCQ = CanonicalQuery::canonicalize(
- _opCtx, std::move(qr), _expCtx, _extensionsCallback, allowedMatcherFeatures);
+ auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx,
+ std::move(findCommand),
+ static_cast<bool>(_request->explain()),
+ _expCtx,
+ _extensionsCallback,
+ allowedMatcherFeatures);
if (statusWithCQ.isOK()) {
_canonicalQuery = std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/db/pipeline/aggregation_request_helper.cpp b/src/mongo/db/pipeline/aggregation_request_helper.cpp
index 6d575759482..a3b574566bd 100644
--- a/src/mongo/db/pipeline/aggregation_request_helper.cpp
+++ b/src/mongo/db/pipeline/aggregation_request_helper.cpp
@@ -37,7 +37,7 @@
#include "mongo/db/exec/document_value/document.h"
#include "mongo/db/exec/document_value/value.h"
#include "mongo/db/query/cursor_request.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/storage/storage_options.h"
#include "mongo/idl/command_generic_argument.h"
diff --git a/src/mongo/db/pipeline/aggregation_request_test.cpp b/src/mongo/db/pipeline/aggregation_request_test.cpp
index 8dac4105fb3..3adb9219d20 100644
--- a/src/mongo/db/pipeline/aggregation_request_test.cpp
+++ b/src/mongo/db/pipeline/aggregation_request_test.cpp
@@ -39,7 +39,7 @@
#include "mongo/db/exec/document_value/document_value_test_util.h"
#include "mongo/db/exec/document_value/value.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
@@ -221,7 +221,7 @@ TEST(AggregationRequestTest, ShouldSerializeOptionalValuesIfSet) {
{AggregateCommand::kPipelineFieldName, std::vector<Value>{}},
{AggregateCommand::kAllowDiskUseFieldName, true},
{AggregateCommand::kCursorFieldName, Value(Document({{kBatchSizeFieldName, 10}}))},
- {QueryRequest::cmdOptionMaxTimeMS, 10},
+ {query_request_helper::cmdOptionMaxTimeMS, 10},
{AggregateCommand::kBypassDocumentValidationFieldName, true},
{repl::ReadConcernArgs::kReadConcernFieldName, readConcernObj},
{AggregateCommand::kCollationFieldName, collationObj},
@@ -229,7 +229,7 @@ TEST(AggregationRequestTest, ShouldSerializeOptionalValuesIfSet) {
{AggregateCommand::kLetFieldName, letParamsObj},
{AggregateCommand::kNeedsMergeFieldName, true},
{AggregateCommand::kFromMongosFieldName, true},
- {QueryRequest::kUnwrappedReadPrefField, readPrefObj},
+ {query_request_helper::kUnwrappedReadPrefField, readPrefObj},
{AggregateCommand::kRequestReshardingResumeTokenFieldName, true},
{AggregateCommand::kIsMapReduceCommandFieldName, true},
{AggregateCommand::kCollectionUUIDFieldName, uuid}};
diff --git a/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp b/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp
index 2c06c7c3497..e2ea85834e0 100644
--- a/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp
+++ b/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp
@@ -45,7 +45,7 @@
#include "mongo/db/query/cursor_response.h"
#include "mongo/db/query/getmore_request.h"
#include "mongo/db/query/query_knobs_gen.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/executor/network_interface_mock.h"
#include "mongo/executor/task_executor.h"
#include "mongo/executor/thread_pool_task_executor_test_fixture.h"
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 059217598a8..bf2923130ed 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -203,32 +203,34 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe
const AggregateCommand* aggRequest,
const size_t plannerOpts,
const MatchExpressionParser::AllowedFeatureSet& matcherFeatures) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setTailableMode(expCtx->tailableMode);
- qr->setFilter(queryObj);
- qr->setProj(projectionObj);
- qr->setSort(sortObj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ query_request_helper::setTailableMode(expCtx->tailableMode, findCommand.get());
+ findCommand->setFilter(queryObj.getOwned());
+ findCommand->setProjection(projectionObj.getOwned());
+ findCommand->setSort(sortObj.getOwned());
if (auto skip = skipThenLimit.getSkip()) {
- qr->setSkip(static_cast<std::int64_t>(*skip));
+ findCommand->setSkip(static_cast<std::int64_t>(*skip));
}
if (auto limit = skipThenLimit.getLimit()) {
- qr->setLimit(static_cast<std::int64_t>(*limit));
+ findCommand->setLimit(static_cast<std::int64_t>(*limit));
}
+ bool isExplain = false;
if (aggRequest) {
- qr->setExplain(static_cast<bool>(aggRequest->getExplain()));
- qr->setHint(aggRequest->getHint().value_or(BSONObj()));
+ findCommand->setHint(aggRequest->getHint().value_or(BSONObj()).getOwned());
+ isExplain = static_cast<bool>(aggRequest->getExplain());
}
// The collation on the ExpressionContext has been resolved to either the user-specified
// collation or the collection default. This BSON should never be empty even if the resolved
// collator is simple.
- qr->setCollation(expCtx->getCollatorBSON());
+ findCommand->setCollation(expCtx->getCollatorBSON().getOwned());
const ExtensionsCallbackReal extensionsCallback(expCtx->opCtx, &nss);
auto cq = CanonicalQuery::canonicalize(expCtx->opCtx,
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx,
extensionsCallback,
matcherFeatures,
diff --git a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp
index 6d48014b8ed..b07e0b3caec 100644
--- a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp
+++ b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp
@@ -233,7 +233,8 @@ void ReplicaSetNodeProcessInterface::_attachGenericCommandArgs(OperationContext*
auto maxTimeMS = opCtx->getRemainingMaxTimeMillis();
if (maxTimeMS != Milliseconds::max()) {
- cmd->append(QueryRequest::cmdOptionMaxTimeMS, durationCount<Milliseconds>(maxTimeMS));
+ cmd->append(query_request_helper::cmdOptionMaxTimeMS,
+ durationCount<Milliseconds>(maxTimeMS));
}
logical_session_id_helpers::serializeLsidAndTxnNumber(opCtx, cmd);
diff --git a/src/mongo/db/pipeline/sharded_agg_helpers.cpp b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
index ec72dceff96..3bec7700e30 100644
--- a/src/mongo/db/pipeline/sharded_agg_helpers.cpp
+++ b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
@@ -79,8 +79,8 @@ Document wrapAggAsExplain(Document aggregateCommand, ExplainOptions::Verbosity v
MutableDocument explainCommandBuilder;
explainCommandBuilder["explain"] = Value(aggregateCommand);
// Downstream host targeting code expects queryOptions at the top level of the command object.
- explainCommandBuilder[QueryRequest::kUnwrappedReadPrefField] =
- Value(aggregateCommand[QueryRequest::kUnwrappedReadPrefField]);
+ explainCommandBuilder[query_request_helper::kUnwrappedReadPrefField] =
+ Value(aggregateCommand[query_request_helper::kUnwrappedReadPrefField]);
// readConcern needs to be promoted to the top-level of the request.
explainCommandBuilder[repl::ReadConcernArgs::kReadConcernFieldName] =
diff --git a/src/mongo/db/query/README.md b/src/mongo/db/query/README.md
index ede094cc3d4..ffb98c9fe7a 100644
--- a/src/mongo/db/query/README.md
+++ b/src/mongo/db/query/README.md
@@ -215,9 +215,9 @@ Once we have parsed the command and checked authorization, we move on to parsing
parts of the query. Once again, we will focus on the find and aggregate commands.
### Find command parsing
-The find command is parsed entirely by the IDL. Initially the IDL parser creates a QueryRequest. As
+The find command is parsed entirely by the IDL. Initially the IDL parser creates a FindCommand. As
mentioned above, the IDL parser does all of the required type checking and stores all options for
-the query. The QueryRequest is then turned into a CanonicalQuery. The CanonicalQuery
+the query. The FindCommand is then turned into a CanonicalQuery. The CanonicalQuery
parses the collation and the filter while just holding the rest of the IDL parsed fields.
The parsing of the collation is straightforward: for each field that is allowed to be in the object,
we check for that field and then build the collation from the parsed fields.
@@ -270,7 +270,7 @@ give a summary of how each is parsed, but not get into the same level of detail.
* count : Parsed by IDL and then turned into a CountStage which can be executed in a similar way to
a find command.
* distinct : The distinct specific arguments are parsed by IDL, and the generic command arguments
- are parsed by custom code. They are then combined into a QueryRequest (mentioned above),
+ are parsed by custom code. They are then combined into a FindCommand (mentioned above),
canonicalized, packaged into a ParsedDistinct, which is eventually turned into an executable
stage.
* mapReduce : Parsed by IDL and then turned into an equivalent aggregation command.
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index ed2627eab26..6672d91e65d 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -177,7 +177,7 @@ env.Library(
source=[
"distinct_command.idl",
"find_command.idl",
- "query_request.cpp",
+ "query_request_helper.cpp",
"max_time_ms_parser.cpp",
"tailable_mode.cpp",
"tailable_mode.idl",
diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp
index 26824999f04..2b24dac9f9a 100644
--- a/src/mongo/db/query/canonical_query.cpp
+++ b/src/mongo/db/query/canonical_query.cpp
@@ -65,33 +65,35 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
const ExtensionsCallback& extensionsCallback,
MatchExpressionParser::AllowedFeatureSet allowedFeatures) {
- // Make QueryRequest.
- auto qrStatus = QueryRequest::fromLegacyQueryMessage(qm);
- if (!qrStatus.isOK()) {
- return qrStatus.getStatus();
+ bool explain = false;
+ // Make FindCommand.
+ auto status = query_request_helper::fromLegacyQueryMessage(qm, &explain);
+ if (!status.isOK()) {
+ return status.getStatus();
}
return CanonicalQuery::canonicalize(
- opCtx, std::move(qrStatus.getValue()), expCtx, extensionsCallback, allowedFeatures);
+ opCtx, std::move(status.getValue()), explain, expCtx, extensionsCallback, allowedFeatures);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
OperationContext* opCtx,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
+ bool explain,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
const ExtensionsCallback& extensionsCallback,
MatchExpressionParser::AllowedFeatureSet allowedFeatures,
const ProjectionPolicies& projectionPolicies) {
- auto qrStatus = qr->validate();
- if (!qrStatus.isOK()) {
- return qrStatus;
+ auto status = query_request_helper::validateFindCommand(*findCommand);
+ if (!status.isOK()) {
+ return status;
}
std::unique_ptr<CollatorInterface> collator;
- if (!qr->getCollation().isEmpty()) {
+ if (!findCommand->getCollation().isEmpty()) {
auto statusWithCollator = CollatorFactoryInterface::get(opCtx->getServiceContext())
- ->makeFromBSON(qr->getCollation());
+ ->makeFromBSON(findCommand->getCollation());
if (!statusWithCollator.isOK()) {
return statusWithCollator.getStatus();
}
@@ -101,14 +103,15 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// Make MatchExpression.
boost::intrusive_ptr<ExpressionContext> newExpCtx;
if (!expCtx.get()) {
+ invariant(findCommand->getNamespaceOrUUID().nss());
newExpCtx = make_intrusive<ExpressionContext>(opCtx,
std::move(collator),
- qr->nss(),
- qr->getLegacyRuntimeConstants(),
- qr->getLetParameters());
+ *findCommand->getNamespaceOrUUID().nss(),
+ findCommand->getLegacyRuntimeConstants(),
+ findCommand->getLet());
} else {
newExpCtx = expCtx;
- // A collator can enter through both the QueryRequest and ExpressionContext arguments.
+ // A collator can enter through both the FindCommand and ExpressionContext arguments.
// This invariant ensures that both collators are the same because downstream we
// pull the collator from only one of the ExpressionContext carrier.
if (collator.get() && expCtx->getCollator()) {
@@ -118,17 +121,19 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// Make the CQ we'll hopefully return.
std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());
+ cq->setExplain(explain);
StatusWithMatchExpression statusWithMatcher = [&]() -> StatusWithMatchExpression {
if (getTestCommandsEnabled() && internalQueryEnableCSTParser.load()) {
try {
- return cst::parseToMatchExpression(qr->getFilter(), newExpCtx, extensionsCallback);
+ return cst::parseToMatchExpression(
+ findCommand->getFilter(), newExpCtx, extensionsCallback);
} catch (const DBException& ex) {
return ex.toStatus();
}
} else {
return MatchExpressionParser::parse(
- qr->getFilter(), newExpCtx, extensionsCallback, allowedFeatures);
+ findCommand->getFilter(), newExpCtx, extensionsCallback, allowedFeatures);
}
}();
if (!statusWithMatcher.isOK()) {
@@ -139,7 +144,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
Status initStatus =
cq->init(opCtx,
std::move(newExpCtx),
- std::move(qr),
+ std::move(findCommand),
parsingCanProduceNoopMatchNodes(extensionsCallback, allowedFeatures),
std::move(me),
projectionPolicies);
@@ -153,24 +158,24 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
OperationContext* opCtx, const CanonicalQuery& baseQuery, MatchExpression* root) {
- auto qr = std::make_unique<QueryRequest>(baseQuery.nss());
+ auto findCommand = std::make_unique<FindCommand>(baseQuery.nss());
BSONObjBuilder builder;
root->serialize(&builder, true);
- 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;
+ findCommand->setFilter(builder.obj());
+ findCommand->setProjection(baseQuery.getFindCommand().getProjection().getOwned());
+ findCommand->setSort(baseQuery.getFindCommand().getSort().getOwned());
+ findCommand->setCollation(baseQuery.getFindCommand().getCollation().getOwned());
+ auto status = query_request_helper::validateFindCommand(*findCommand);
+ if (!status.isOK()) {
+ return status;
}
// Make the CQ we'll hopefully return.
std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());
+ cq->setExplain(baseQuery.getExplain());
Status initStatus = cq->init(opCtx,
baseQuery.getExpCtx(),
- std::move(qr),
+ std::move(findCommand),
baseQuery.canHaveNoopMatchNodes(),
root->shallowClone(),
ProjectionPolicies::findProjectionPolicies());
@@ -183,28 +188,31 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
Status CanonicalQuery::init(OperationContext* opCtx,
boost::intrusive_ptr<ExpressionContext> expCtx,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
bool canHaveNoopMatchNodes,
std::unique_ptr<MatchExpression> root,
const ProjectionPolicies& projectionPolicies) {
_expCtx = expCtx;
- _qr = std::move(qr);
+ _findCommand = std::move(findCommand);
_canHaveNoopMatchNodes = canHaveNoopMatchNodes;
// Normalize and validate tree.
_root = MatchExpression::normalize(std::move(root));
- auto validStatus = isValid(_root.get(), *_qr);
+ auto validStatus = isValid(_root.get(), *_findCommand);
if (!validStatus.isOK()) {
return validStatus.getStatus();
}
auto unavailableMetadata = validStatus.getValue();
// Validate the projection if there is one.
- if (!_qr->getProj().isEmpty()) {
+ if (!_findCommand->getProjection().isEmpty()) {
try {
- _proj.emplace(projection_ast::parse(
- expCtx, _qr->getProj(), _root.get(), _qr->getFilter(), projectionPolicies));
+ _proj.emplace(projection_ast::parse(expCtx,
+ _findCommand->getProjection(),
+ _root.get(),
+ _findCommand->getFilter(),
+ projectionPolicies));
// Fail if any of the projection's dependencies are unavailable.
DepsTracker{unavailableMetadata}.requestMetadata(_proj->metadataDeps());
@@ -216,7 +224,7 @@ Status CanonicalQuery::init(OperationContext* opCtx,
}
if (_proj && _proj->metadataDeps()[DocumentMetadataFields::kSortKey] &&
- _qr->getSort().isEmpty()) {
+ _findCommand->getSort().isEmpty()) {
return Status(ErrorCodes::BadValue, "cannot use sortKey $meta projection without a sort");
}
@@ -228,7 +236,7 @@ Status CanonicalQuery::init(OperationContext* opCtx,
}
// If the 'returnKey' option is set, then the plan should produce index key metadata.
- if (_qr->returnKey()) {
+ if (_findCommand->getReturnKey()) {
_metadataDeps.set(DocumentMetadataFields::kIndexKey);
}
@@ -236,7 +244,7 @@ Status CanonicalQuery::init(OperationContext* opCtx,
}
void CanonicalQuery::initSortPattern(QueryMetadataBitSet unavailableMetadata) {
- if (_qr->getSort().isEmpty()) {
+ if (_findCommand->getSort().isEmpty()) {
return;
}
@@ -246,15 +254,15 @@ void CanonicalQuery::initSortPattern(QueryMetadataBitSet unavailableMetadata) {
// We have already validated that if there is a $natural sort and a hint, that the hint
// also specifies $natural with the same direction. Therefore, it is safe to clear the $natural
// sort and rewrite it as a $natural hint.
- if (_qr->getSort()[QueryRequest::kNaturalSortField]) {
- _qr->setHint(_qr->getSort());
- _qr->setSort(BSONObj{});
+ if (_findCommand->getSort()[query_request_helper::kNaturalSortField]) {
+ _findCommand->setHint(_findCommand->getSort().getOwned());
+ _findCommand->setSort(BSONObj{});
}
if (getTestCommandsEnabled() && internalQueryEnableCSTParser.load()) {
- _sortPattern = cst::parseToSortPattern(_qr->getSort(), _expCtx);
+ _sortPattern = cst::parseToSortPattern(_findCommand->getSort(), _expCtx);
} else {
- _sortPattern = SortPattern{_qr->getSort(), _expCtx};
+ _sortPattern = SortPattern{_findCommand->getSort(), _expCtx};
}
_metadataDeps |= _sortPattern->metadataDeps(unavailableMetadata);
@@ -334,7 +342,7 @@ bool hasNodeInSubtree(MatchExpression* root,
}
StatusWith<QueryMetadataBitSet> CanonicalQuery::isValid(MatchExpression* root,
- const QueryRequest& request) {
+ const FindCommand& findCommand) {
QueryMetadataBitSet unavailableMetadata{};
// There can only be one TEXT. If there is a TEXT, it cannot appear inside a NOR.
@@ -378,9 +386,9 @@ StatusWith<QueryMetadataBitSet> CanonicalQuery::isValid(MatchExpression* root,
unavailableMetadata |= DepsTracker::kAllGeoNearData;
}
- const BSONObj& sortObj = request.getSort();
+ const BSONObj& sortObj = findCommand.getSort();
BSONElement sortNaturalElt = sortObj["$natural"];
- const BSONObj& hintObj = request.getHint();
+ const BSONObj& hintObj = findCommand.getHint();
BSONElement hintNaturalElt = hintObj["$natural"];
if (sortNaturalElt && sortObj.nFields() != 1) {
@@ -422,12 +430,12 @@ StatusWith<QueryMetadataBitSet> CanonicalQuery::isValid(MatchExpression* root,
}
// TEXT and tailable are incompatible.
- if (numText > 0 && request.isTailable()) {
+ if (numText > 0 && findCommand.getTailable()) {
return Status(ErrorCodes::BadValue, "text and tailable cursor not allowed in same query");
}
// NEAR and tailable are incompatible.
- if (numGeoNear > 0 && request.isTailable()) {
+ if (numGeoNear > 0 && findCommand.getTailable()) {
return Status(ErrorCodes::BadValue,
"Tailable cursors and geo $near cannot be used together");
}
@@ -448,59 +456,78 @@ StatusWith<QueryMetadataBitSet> CanonicalQuery::isValid(MatchExpression* root,
return unavailableMetadata;
}
+int CanonicalQuery::getOptions() const {
+ int options = 0;
+ if (_findCommand->getTailable()) {
+ options |= QueryOption_CursorTailable;
+ }
+ if (_findCommand->getAwaitData()) {
+ options |= QueryOption_AwaitData;
+ }
+ if (_findCommand->getNoCursorTimeout()) {
+ options |= QueryOption_NoCursorTimeout;
+ }
+ if (_findCommand->getAllowPartialResults()) {
+ options |= QueryOption_PartialResults;
+ }
+ return options;
+}
+
std::string CanonicalQuery::toString() const {
str::stream ss;
- ss << "ns=" << _qr->nss().ns();
+ ss << "ns=" << _findCommand->getNamespaceOrUUID().nss().value_or(NamespaceString()).ns();
- if (_qr->getBatchSize()) {
- ss << " batchSize=" << *_qr->getBatchSize();
+ if (_findCommand->getBatchSize()) {
+ ss << " batchSize=" << *_findCommand->getBatchSize();
}
- if (_qr->getLimit()) {
- ss << " limit=" << *_qr->getLimit();
+ if (_findCommand->getLimit()) {
+ ss << " limit=" << *_findCommand->getLimit();
}
- if (_qr->getSkip()) {
- ss << " skip=" << *_qr->getSkip();
+ if (_findCommand->getSkip()) {
+ ss << " skip=" << *_findCommand->getSkip();
}
- if (_qr->getNToReturn()) {
- ss << " ntoreturn=" << *_qr->getNToReturn() << '\n';
+ if (_findCommand->getNtoreturn()) {
+ ss << " ntoreturn=" << *_findCommand->getNtoreturn() << '\n';
}
// The expression tree puts an endl on for us.
ss << "Tree: " << _root->debugString();
- ss << "Sort: " << _qr->getSort().toString() << '\n';
- ss << "Proj: " << _qr->getProj().toString() << '\n';
- if (!_qr->getCollation().isEmpty()) {
- ss << "Collation: " << _qr->getCollation().toString() << '\n';
+ ss << "Sort: " << _findCommand->getSort().toString() << '\n';
+ ss << "Proj: " << _findCommand->getProjection().toString() << '\n';
+ if (!_findCommand->getCollation().isEmpty()) {
+ ss << "Collation: " << _findCommand->getCollation().toString() << '\n';
}
return ss;
}
std::string CanonicalQuery::toStringShort() const {
str::stream ss;
- ss << "ns: " << _qr->nss().ns() << " query: " << _qr->getFilter().toString()
- << " sort: " << _qr->getSort().toString() << " projection: " << _qr->getProj().toString();
+ ss << "ns: " << _findCommand->getNamespaceOrUUID().nss().value_or(NamespaceString()).ns()
+ << " query: " << _findCommand->getFilter().toString()
+ << " sort: " << _findCommand->getSort().toString()
+ << " projection: " << _findCommand->getProjection().toString();
- if (!_qr->getCollation().isEmpty()) {
- ss << " collation: " << _qr->getCollation().toString();
+ if (!_findCommand->getCollation().isEmpty()) {
+ ss << " collation: " << _findCommand->getCollation().toString();
}
- if (_qr->getBatchSize()) {
- ss << " batchSize: " << *_qr->getBatchSize();
+ if (_findCommand->getBatchSize()) {
+ ss << " batchSize: " << *_findCommand->getBatchSize();
}
- if (_qr->getLimit()) {
- ss << " limit: " << *_qr->getLimit();
+ if (_findCommand->getLimit()) {
+ ss << " limit: " << *_findCommand->getLimit();
}
- if (_qr->getSkip()) {
- ss << " skip: " << *_qr->getSkip();
+ if (_findCommand->getSkip()) {
+ ss << " skip: " << *_findCommand->getSkip();
}
- if (_qr->getNToReturn()) {
- ss << " ntoreturn=" << *_qr->getNToReturn();
+ if (_findCommand->getNtoreturn()) {
+ ss << " ntoreturn=" << *_findCommand->getNtoreturn();
}
return ss;
diff --git a/src/mongo/db/query/canonical_query.h b/src/mongo/db/query/canonical_query.h
index ddcd5c731d7..4b148557710 100644
--- a/src/mongo/db/query/canonical_query.h
+++ b/src/mongo/db/query/canonical_query.h
@@ -38,7 +38,7 @@
#include "mongo/db/query/collation/collator_interface.h"
#include "mongo/db/query/projection.h"
#include "mongo/db/query/projection_policies.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/query/sort_pattern.h"
namespace mongo {
@@ -77,7 +77,8 @@ public:
*/
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
OperationContext* opCtx,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
+ bool explain = false,
const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr,
const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(),
MatchExpressionParser::AllowedFeatureSet allowedFeatures =
@@ -117,13 +118,14 @@ public:
* error.
*/
static StatusWith<QueryMetadataBitSet> isValid(MatchExpression* root,
- const QueryRequest& request);
+ const FindCommand& findCommand);
- const NamespaceString& nss() const {
- return _qr->nss();
+ const NamespaceString nss() const {
+ invariant(_findCommand->getNamespaceOrUUID().nss());
+ return *_findCommand->getNamespaceOrUUID().nss();
}
- const std::string& ns() const {
- return _qr->nss().ns();
+ const std::string ns() const {
+ return nss().ns();
}
//
@@ -133,10 +135,10 @@ public:
return _root.get();
}
const BSONObj& getQueryObj() const {
- return _qr->getFilter();
+ return _findCommand->getFilter();
}
- const QueryRequest& getQueryRequest() const {
- return *_qr;
+ const FindCommand& getFindCommand() const {
+ return *_findCommand;
}
/**
@@ -209,6 +211,19 @@ public:
return _canHaveNoopMatchNodes;
}
+ /**
+ * Return options as a bit vector.
+ */
+ int getOptions() const;
+
+ bool getExplain() const {
+ return _explain;
+ }
+
+ void setExplain(bool explain) {
+ _explain = explain;
+ }
+
auto& getExpCtx() const {
return _expCtx;
}
@@ -222,7 +237,7 @@ private:
Status init(OperationContext* opCtx,
boost::intrusive_ptr<ExpressionContext> expCtx,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
bool canHaveNoopMatchNodes,
std::unique_ptr<MatchExpression> root,
const ProjectionPolicies& projectionPolicies);
@@ -235,7 +250,7 @@ private:
boost::intrusive_ptr<ExpressionContext> _expCtx;
- std::unique_ptr<QueryRequest> _qr;
+ std::unique_ptr<FindCommand> _findCommand;
std::unique_ptr<MatchExpression> _root;
@@ -247,6 +262,8 @@ private:
QueryMetadataBitSet _metadataDeps;
bool _canHaveNoopMatchNodes = false;
+
+ bool _explain = false;
};
} // namespace mongo
diff --git a/src/mongo/db/query/canonical_query_encoder.cpp b/src/mongo/db/query/canonical_query_encoder.cpp
index e8ef4308158..41e7af395f8 100644
--- a/src/mongo/db/query/canonical_query_encoder.cpp
+++ b/src/mongo/db/query/canonical_query_encoder.cpp
@@ -480,7 +480,7 @@ void encodeKeyForMatch(const MatchExpression* tree, StringBuilder* keyBuilder) {
/**
* Encodes sort order into cache key.
* Sort order is normalized because it provided by
- * QueryRequest.
+ * FindCommand.
*/
void encodeKeyForSort(const BSONObj& sortObj, StringBuilder* keyBuilder) {
if (sortObj.isEmpty()) {
@@ -493,7 +493,7 @@ void encodeKeyForSort(const BSONObj& sortObj, StringBuilder* keyBuilder) {
while (it.more()) {
BSONElement elt = it.next();
// $meta text score
- if (QueryRequest::isTextScoreMeta(elt)) {
+ if (query_request_helper::isTextScoreMeta(elt)) {
*keyBuilder << "t";
}
// Ascending
@@ -567,7 +567,7 @@ namespace canonical_query_encoder {
CanonicalQuery::QueryShapeString encode(const CanonicalQuery& cq) {
StringBuilder keyBuilder;
encodeKeyForMatch(cq.root(), &keyBuilder);
- encodeKeyForSort(cq.getQueryRequest().getSort(), &keyBuilder);
+ encodeKeyForSort(cq.getFindCommand().getSort(), &keyBuilder);
encodeKeyForProj(cq.getProj(), &keyBuilder);
encodeCollation(cq.getCollator(), &keyBuilder);
diff --git a/src/mongo/db/query/canonical_query_encoder_test.cpp b/src/mongo/db/query/canonical_query_encoder_test.cpp
index f10c0c17e64..f54f7b7398b 100644
--- a/src/mongo/db/query/canonical_query_encoder_test.cpp
+++ b/src/mongo/db/query/canonical_query_encoder_test.cpp
@@ -55,15 +55,16 @@ unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
- qr->setCollation(collation);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query.getOwned());
+ findCommand->setSort(sort.getOwned());
+ findCommand->setProjection(proj.getOwned());
+ findCommand->setCollation(collation.getOwned());
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp
index b40f31d6f60..2f0f2e02d4a 100644
--- a/src/mongo/db/query/canonical_query_test.cpp
+++ b/src/mongo/db/query/canonical_query_test.cpp
@@ -98,22 +98,18 @@ TEST(CanonicalQueryTest, IsValidSortKeyMetaProjection) {
// Passing a sortKey meta-projection without a sort is an error.
{
- const bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(
- fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}, '$db': 'test'}"),
- isExplain);
- auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(
+ fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}, '$db': 'test'}"));
+ auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_NOT_OK(cq.getStatus());
}
// Should be able to successfully create a CQ when there is a sort.
{
- const bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(
fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}, sort: {bar: 1}, "
- "'$db': 'test'}"),
- isExplain);
- auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ "'$db': 'test'}"));
+ auto cq = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_OK(cq.getStatus());
}
}
@@ -183,11 +179,15 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
- auto statusWithCQ = CanonicalQuery::canonicalize(
- opCtx.get(), std::move(qr), nullptr, ExtensionsCallbackNoop(), allowedFeatures);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(),
+ std::move(findCommand),
+ false,
+ nullptr,
+ ExtensionsCallbackNoop(),
+ allowedFeatures);
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
@@ -199,11 +199,11 @@ std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projStr));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projStr));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -273,27 +273,29 @@ TEST(CanonicalQueryTest, CanonicalizeFromBaseQuery) {
const std::string cmdStr =
"{find:'bogusns', filter:{$or:[{a:1,b:1},{a:1,c:1}]}, projection:{a:1}, sort:{b:1}, '$db': "
"'test'}";
- auto qr = QueryRequest::makeFromFindCommandForTests(fromjson(cmdStr), isExplain);
- auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(fromjson(cmdStr));
+ auto baseCq =
+ assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand), isExplain));
MatchExpression* firstClauseExpr = baseCq->root()->getChild(0);
auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr));
BSONObjBuilder expectedFilter;
firstClauseExpr->serialize(&expectedFilter);
- ASSERT_BSONOBJ_EQ(childCq->getQueryRequest().getFilter(), expectedFilter.obj());
+ ASSERT_BSONOBJ_EQ(childCq->getFindCommand().getFilter(), expectedFilter.obj());
- ASSERT_BSONOBJ_EQ(childCq->getQueryRequest().getProj(), baseCq->getQueryRequest().getProj());
- ASSERT_BSONOBJ_EQ(childCq->getQueryRequest().getSort(), baseCq->getQueryRequest().getSort());
- ASSERT_TRUE(childCq->getQueryRequest().isExplain());
+ ASSERT_BSONOBJ_EQ(childCq->getFindCommand().getProjection(),
+ baseCq->getFindCommand().getProjection());
+ ASSERT_BSONOBJ_EQ(childCq->getFindCommand().getSort(), baseCq->getFindCommand().getSort());
+ ASSERT_TRUE(childCq->getExplain());
}
TEST(CanonicalQueryTest, CanonicalQueryFromQRWithNoCollation) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand)));
ASSERT_TRUE(cq->getCollator() == nullptr);
}
@@ -301,10 +303,10 @@ TEST(CanonicalQueryTest, CanonicalQueryFromQRWithCollation) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setCollation(BSON("locale"
- << "reverse"));
- auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setCollation(BSON("locale"
+ << "reverse"));
+ auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand)));
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ASSERT_TRUE(CollatorInterface::collatorsMatch(cq->getCollator(), &collator));
}
@@ -313,9 +315,9 @@ TEST(CanonicalQueryTest, CanonicalQueryFromBaseQueryWithNoCollation) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}"));
- auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}"));
+ auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand)));
MatchExpression* firstClauseExpr = baseCq->root()->getChild(0);
auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr));
ASSERT_TRUE(baseCq->getCollator() == nullptr);
@@ -326,11 +328,11 @@ TEST(CanonicalQueryTest, CanonicalQueryFromBaseQueryWithCollation) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}"));
- qr->setCollation(BSON("locale"
- << "reverse"));
- auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{$or:[{a:1,b:1},{a:1,c:1}]}"));
+ findCommand->setCollation(BSON("locale"
+ << "reverse"));
+ auto baseCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand)));
MatchExpression* firstClauseExpr = baseCq->root()->getChild(0);
auto childCq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), *baseCq, firstClauseExpr));
ASSERT(baseCq->getCollator());
@@ -342,9 +344,9 @@ TEST(CanonicalQueryTest, SettingCollatorUpdatesCollatorAndMatchExpression) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{a: 'foo', b: {$in: ['bar', 'baz']}}"));
- auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{a: 'foo', b: {$in: ['bar', 'baz']}}"));
+ auto cq = assertGet(CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand)));
ASSERT_EQUALS(2U, cq->root()->numChildren());
auto firstChild = cq->root()->getChild(0);
auto secondChild = cq->root()->getChild(1);
@@ -396,12 +398,13 @@ void assertValidSortOrder(BSONObj sort, BSONObj filter = BSONObj{}) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(filter);
- qr->setSort(sort);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
+ findCommand->setSort(sort);
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
nullptr,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -421,9 +424,9 @@ void assertInvalidSortOrder(BSONObj sort) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setSort(sort);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setSort(sort);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_NOT_OK(statusWithCQ.getStatus());
}
diff --git a/src/mongo/db/query/classic_stage_builder.cpp b/src/mongo/db/query/classic_stage_builder.cpp
index a70ff51848f..5a5d2f311dd 100644
--- a/src/mongo/db/query/classic_stage_builder.cpp
+++ b/src/mongo/db/query/classic_stage_builder.cpp
@@ -161,7 +161,7 @@ std::unique_ptr<PlanStage> ClassicStageBuilder::build(const QuerySolutionNode* r
auto pn = static_cast<const ProjectionNodeDefault*>(root);
auto childStage = build(pn->children[0]);
return std::make_unique<ProjectionStageDefault>(_cq.getExpCtx(),
- _cq.getQueryRequest().getProj(),
+ _cq.getFindCommand().getProjection(),
_cq.getProj(),
_ws,
std::move(childStage));
@@ -170,7 +170,7 @@ std::unique_ptr<PlanStage> ClassicStageBuilder::build(const QuerySolutionNode* r
auto pn = static_cast<const ProjectionNodeCovered*>(root);
auto childStage = build(pn->children[0]);
return std::make_unique<ProjectionStageCovered>(_cq.getExpCtxRaw(),
- _cq.getQueryRequest().getProj(),
+ _cq.getFindCommand().getProjection(),
_cq.getProj(),
_ws,
std::move(childStage),
@@ -180,7 +180,7 @@ std::unique_ptr<PlanStage> ClassicStageBuilder::build(const QuerySolutionNode* r
auto pn = static_cast<const ProjectionNodeSimple*>(root);
auto childStage = build(pn->children[0]);
return std::make_unique<ProjectionStageSimple>(_cq.getExpCtxRaw(),
- _cq.getQueryRequest().getProj(),
+ _cq.getFindCommand().getProjection(),
_cq.getProj(),
_ws,
std::move(childStage));
diff --git a/src/mongo/db/query/classic_stage_builder_test.cpp b/src/mongo/db/query/classic_stage_builder_test.cpp
index 0fd2f44faa0..b7761ef474f 100644
--- a/src/mongo/db/query/classic_stage_builder_test.cpp
+++ b/src/mongo/db/query/classic_stage_builder_test.cpp
@@ -68,9 +68,10 @@ public:
* Builds a PlanStage using the given WorkingSet and QuerySolution.
*/
std::unique_ptr<PlanStage> buildPlanStage(std::unique_ptr<QuerySolution> querySolution) {
- auto qr = std::make_unique<QueryRequest>(kNss);
+ auto findCommand = std::make_unique<FindCommand>(kNss);
auto expCtx = make_intrusive<ExpressionContext>(opCtx(), nullptr, kNss);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr), expCtx);
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, expCtx);
ASSERT_OK(statusWithCQ.getStatus());
stage_builder::ClassicStageBuilder builder{
diff --git a/src/mongo/db/query/count_command_as_aggregation_command.cpp b/src/mongo/db/query/count_command_as_aggregation_command.cpp
index 418fe629a6a..668baeb7c6b 100644
--- a/src/mongo/db/query/count_command_as_aggregation_command.cpp
+++ b/src/mongo/db/query/count_command_as_aggregation_command.cpp
@@ -31,7 +31,7 @@
#include "mongo/db/query/count_command_as_aggregation_command.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -101,7 +101,8 @@ StatusWith<BSONObj> countCommandAsAggregationCommand(const CountCommand& cmd,
if (auto unwrapped = cmd.getQueryOptions()) {
if (!unwrapped->isEmpty()) {
- aggregationBuilder.append(QueryRequest::kUnwrappedReadPrefField, unwrapped.get());
+ aggregationBuilder.append(query_request_helper::kUnwrappedReadPrefField,
+ unwrapped.get());
}
}
diff --git a/src/mongo/db/query/count_request.cpp b/src/mongo/db/query/count_request.cpp
index 93a645841e3..0b6f1a68a71 100644
--- a/src/mongo/db/query/count_request.cpp
+++ b/src/mongo/db/query/count_request.cpp
@@ -33,7 +33,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/matcher/expression_parser.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
namespace mongo {
namespace count_request {
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index 67e439e7e53..6e919f51a1a 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -85,8 +85,8 @@ bool shouldSaveCursor(OperationContext* opCtx,
const CollectionPtr& collection,
PlanExecutor::ExecState finalState,
PlanExecutor* exec) {
- const QueryRequest& qr = exec->getCanonicalQuery()->getQueryRequest();
- if (qr.isSingleBatch()) {
+ const FindCommand& findCommand = exec->getCanonicalQuery()->getFindCommand();
+ if (findCommand.getSingleBatch()) {
return false;
}
@@ -96,7 +96,7 @@ bool shouldSaveCursor(OperationContext* opCtx,
// SERVER-13955: we should be able to create a tailable cursor that waits on
// an empty collection. Right now we do not keep a cursor if the collection
// has zero records.
- if (qr.isTailable()) {
+ if (findCommand.getTailable()) {
return collection && collection->numRecords(opCtx) != 0U;
}
@@ -614,30 +614,34 @@ bool runQuery(OperationContext* opCtx,
// Parse, canonicalize, plan, transcribe, and get a plan executor.
AutoGetCollectionForReadCommandMaybeLockFree collection(
opCtx, nss, AutoGetCollectionViewMode::kViewsForbidden);
- const QueryRequest& qr = cq->getQueryRequest();
- opCtx->setExhaust(qr.isExhaust());
+ const bool isExhaust = (q.queryOptions & QueryOption_Exhaust) != 0;
+ opCtx->setExhaust(isExhaust);
{
// Allow the query to run on secondaries if the read preference permits it. If no read
// preference was specified, allow the query to run iff slaveOk has been set.
- const bool slaveOK = qr.hasReadPref()
+ const bool isSecondaryOk = (q.queryOptions & QueryOption_SecondaryOk) != 0;
+ const bool hasReadPref = q.query.hasField(query_request_helper::kWrappedReadPrefField);
+ const bool secondaryOk = hasReadPref
? uassertStatusOK(ReadPreferenceSetting::fromContainingBSON(q.query))
.canRunOnSecondary()
- : qr.isSlaveOk();
- uassertStatusOK(
- repl::ReplicationCoordinator::get(opCtx)->checkCanServeReadsFor(opCtx, nss, slaveOK));
+ : isSecondaryOk;
+ uassertStatusOK(repl::ReplicationCoordinator::get(opCtx)->checkCanServeReadsFor(
+ opCtx, nss, secondaryOk));
}
+ const FindCommand& findCommand = cq->getFindCommand();
// Get the execution plan for the query.
constexpr auto verbosity = ExplainOptions::Verbosity::kExecAllPlans;
- expCtx->explain = qr.isExplain() ? boost::make_optional(verbosity) : boost::none;
+ const bool isExplain = cq->getExplain();
+ expCtx->explain = isExplain ? boost::make_optional(verbosity) : boost::none;
auto exec =
uassertStatusOK(getExecutorLegacyFind(opCtx, &collection.getCollection(), std::move(cq)));
// If it's actually an explain, do the explain and return rather than falling through
// to the normal query execution loop.
- if (qr.isExplain()) {
+ if (isExplain) {
BufBuilder bb;
bb.skip(sizeof(QueryResult::Value));
@@ -666,12 +670,13 @@ bool runQuery(OperationContext* opCtx,
return false;
}
+ int maxTimeMS = findCommand.getMaxTimeMS() ? static_cast<int>(*findCommand.getMaxTimeMS()) : 0;
// Handle query option $maxTimeMS (not used with commands).
- if (qr.getMaxTimeMS() > 0) {
+ if (maxTimeMS > 0) {
uassert(40116,
"Illegal attempt to set operation deadline within DBDirectClient",
!opCtx->getClient()->isInDirectClient());
- opCtx->setDeadlineAfterNowBy(Milliseconds{qr.getMaxTimeMS()}, ErrorCodes::MaxTimeMSExpired);
+ opCtx->setDeadlineAfterNowBy(Milliseconds{maxTimeMS}, ErrorCodes::MaxTimeMSExpired);
}
opCtx->checkForInterrupt(); // May trigger maxTimeAlwaysTimeOut fail point.
@@ -713,12 +718,12 @@ bool runQuery(OperationContext* opCtx,
docUnitsReturned.observeOne(obj.objsize());
- if (FindCommon::enoughForFirstBatch(qr, numResults)) {
+ if (FindCommon::enoughForFirstBatch(findCommand, numResults)) {
LOGV2_DEBUG(20915,
5,
"Enough for first batch",
- "wantMore"_attr = !qr.isSingleBatch(),
- "numToReturn"_attr = qr.getNToReturn().value_or(0),
+ "wantMore"_attr = !findCommand.getSingleBatch(),
+ "numToReturn"_attr = findCommand.getNtoreturn().value_or(0),
"numResults"_attr = numResults);
break;
}
diff --git a/src/mongo/db/query/find_common.cpp b/src/mongo/db/query/find_common.cpp
index 048683f677b..02191c367eb 100644
--- a/src/mongo/db/query/find_common.cpp
+++ b/src/mongo/db/query/find_common.cpp
@@ -37,7 +37,7 @@
#include "mongo/db/curop.h"
#include "mongo/db/curop_failpoint_helpers.h"
#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/logv2/log.h"
#include "mongo/util/assert_util.h"
@@ -58,13 +58,15 @@ MONGO_FAIL_POINT_DEFINE(failGetMoreAfterCursorCheckout);
const OperationContext::Decoration<AwaitDataState> awaitDataState =
OperationContext::declareDecoration<AwaitDataState>();
-bool FindCommon::enoughForFirstBatch(const QueryRequest& qr, long long numDocs) {
- if (!qr.getEffectiveBatchSize()) {
+bool FindCommon::enoughForFirstBatch(const FindCommand& findCommand, long long numDocs) {
+ auto effectiveBatchSize =
+ findCommand.getBatchSize() ? findCommand.getBatchSize() : findCommand.getNtoreturn();
+ if (!effectiveBatchSize) {
// We enforce a default batch size for the initial find if no batch size is specified.
- return numDocs >= QueryRequest::kDefaultBatchSize;
+ return numDocs >= query_request_helper::kDefaultBatchSize;
}
- return numDocs >= qr.getEffectiveBatchSize().value();
+ return numDocs >= effectiveBatchSize.value();
}
bool FindCommon::haveSpaceForNext(const BSONObj& nextDoc, long long numDocs, int bytesBuffered) {
diff --git a/src/mongo/db/query/find_common.h b/src/mongo/db/query/find_common.h
index 44b941f7667..3fc2b9b0e76 100644
--- a/src/mongo/db/query/find_common.h
+++ b/src/mongo/db/query/find_common.h
@@ -54,7 +54,7 @@ extern const OperationContext::Decoration<AwaitDataState> awaitDataState;
class BSONObj;
class CanonicalQuery;
-class QueryRequest;
+class FindCommand;
// Failpoint for making find hang.
extern FailPoint waitInFindBeforeMakingBatch;
@@ -101,7 +101,7 @@ public:
*
* If 'qr' does not have a batchSize, the default batchSize is respected.
*/
- static bool enoughForFirstBatch(const QueryRequest& qr, long long numDocs);
+ static bool enoughForFirstBatch(const FindCommand& findCommand, long long numDocs);
/**
* Returns true if the batchSize for the getMore has been satisfied.
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 19e068ca39c..2251683e71d 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -147,11 +147,11 @@ bool turnIxscanIntoCount(QuerySolution* soln);
* Returns 'true' if 'query' on the given 'collection' can be answered using a special IDHACK plan.
*/
bool isIdHackEligibleQuery(const CollectionPtr& collection, const CanonicalQuery& query) {
- return !query.getQueryRequest().showRecordId() && query.getQueryRequest().getHint().isEmpty() &&
- query.getQueryRequest().getMin().isEmpty() && query.getQueryRequest().getMax().isEmpty() &&
- !query.getQueryRequest().getSkip() &&
- CanonicalQuery::isSimpleIdQuery(query.getQueryRequest().getFilter()) &&
- !query.getQueryRequest().isTailable() &&
+ const auto& findCommand = query.getFindCommand();
+ return !findCommand.getShowRecordId() && findCommand.getHint().isEmpty() &&
+ findCommand.getMin().isEmpty() && findCommand.getMax().isEmpty() &&
+ !findCommand.getSkip() && CanonicalQuery::isSimpleIdQuery(findCommand.getFilter()) &&
+ !findCommand.getTailable() &&
CollatorInterface::collatorsMatch(query.getCollator(), collection->getDefaultCollator());
}
} // namespace
@@ -351,7 +351,7 @@ void fillOutPlannerParams(OperationContext* opCtx,
plannerParams->options |= QueryPlannerParams::SPLIT_LIMITED_SORT;
if (shouldWaitForOplogVisibility(
- opCtx, collection, canonicalQuery->getQueryRequest().isTailable())) {
+ opCtx, collection, canonicalQuery->getFindCommand().getTailable())) {
plannerParams->options |= QueryPlannerParams::OPLOG_SCAN_WAIT_FOR_VISIBLE;
}
}
@@ -578,7 +578,7 @@ public:
// If the canonical query does not have a user-specified collation and no one has given the
// CanonicalQuery a collation already, set it from the collection default.
- if (_cq->getQueryRequest().getCollation().isEmpty() && _cq->getCollator() == nullptr &&
+ if (_cq->getFindCommand().getCollation().isEmpty() && _cq->getCollator() == nullptr &&
_collection->getDefaultCollator()) {
_cq->setCollator(_collection->getDefaultCollator()->clone());
}
@@ -598,7 +598,7 @@ public:
}
// Tailable: If the query requests tailable the collection must be capped.
- if (_cq->getQueryRequest().isTailable() && !_collection->isCapped()) {
+ if (_cq->getFindCommand().getTailable() && !_collection->isCapped()) {
return Status(ErrorCodes::BadValue,
str::stream() << "error processing query: " << _cq->toString()
<< " tailable cursor requested on non capped collection");
@@ -799,10 +799,10 @@ protected:
// Add a SortKeyGeneratorStage if the query requested sortKey metadata.
if (_cq->metadataDeps()[DocumentMetadataFields::kSortKey]) {
stage = std::make_unique<SortKeyGeneratorStage>(
- _cq->getExpCtxRaw(), std::move(stage), _ws, _cq->getQueryRequest().getSort());
+ _cq->getExpCtxRaw(), std::move(stage), _ws, _cq->getFindCommand().getSort());
}
- if (_cq->getQueryRequest().returnKey()) {
+ if (_cq->getFindCommand().getReturnKey()) {
// If returnKey was requested, add ReturnKeyStage to return only the index keys in
// the resulting documents. If a projection was also specified, it will be ignored,
// with the exception the $meta sortKey projection, which can be used along with the
@@ -820,17 +820,19 @@ protected:
// simple inclusion fast path.
// Stuff the right data into the params depending on what proj impl we use.
if (!cqProjection->isSimple()) {
- stage = std::make_unique<ProjectionStageDefault>(_cq->getExpCtxRaw(),
- _cq->getQueryRequest().getProj(),
- _cq->getProj(),
- _ws,
- std::move(stage));
+ stage =
+ std::make_unique<ProjectionStageDefault>(_cq->getExpCtxRaw(),
+ _cq->getFindCommand().getProjection(),
+ _cq->getProj(),
+ _ws,
+ std::move(stage));
} else {
- stage = std::make_unique<ProjectionStageSimple>(_cq->getExpCtxRaw(),
- _cq->getQueryRequest().getProj(),
- _cq->getProj(),
- _ws,
- std::move(stage));
+ stage =
+ std::make_unique<ProjectionStageSimple>(_cq->getExpCtxRaw(),
+ _cq->getFindCommand().getProjection(),
+ _cq->getProj(),
+ _ws,
+ std::move(stage));
}
}
@@ -1112,7 +1114,7 @@ inline bool isQuerySbeCompatible(const CanonicalQuery* const cq, size_t plannerO
const bool isNotCount = !(plannerOptions & QueryPlannerParams::IS_COUNT);
// Specifying 'ntoreturn' in an OP_QUERY style find may result in a QuerySolution with
// ENSURE_SORTED node, which is currently not supported by SBE.
- const bool doesNotNeedEnsureSorted = !cq->getQueryRequest().getNToReturn();
+ const bool doesNotNeedEnsureSorted = !cq->getFindCommand().getNtoreturn();
const bool doesNotContainMetadataRequirements = cq->metadataDeps().none();
const bool doesNotSortOnDottedPath =
!sortPattern || std::all_of(sortPattern->begin(), sortPattern->end(), [](auto&& part) {
@@ -1716,16 +1718,16 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCoun
OperationContext* opCtx = expCtx->opCtx;
std::unique_ptr<WorkingSet> ws = std::make_unique<WorkingSet>();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(request.getQuery());
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(request.getQuery());
auto collation = request.getCollation().value_or(BSONObj());
- qr->setCollation(collation);
- qr->setHint(request.getHint());
- qr->setExplain(explain);
+ findCommand->setCollation(collation);
+ findCommand->setHint(request.getHint());
auto statusWithCQ = CanonicalQuery::canonicalize(
opCtx,
- std::move(qr),
+ std::move(findCommand),
+ explain,
expCtx,
collection ? static_cast<const ExtensionsCallback&>(
ExtensionsCallbackReal(opCtx, &collection->ns()))
@@ -1998,7 +2000,7 @@ QueryPlannerParams fillOutPlannerParamsForDistinct(OperationContext* opCtx,
const bool mayUnwindArrays = !(plannerOptions & QueryPlannerParams::STRICT_DISTINCT_ONLY);
std::unique_ptr<IndexCatalog::IndexIterator> ii =
collection->getIndexCatalog()->getIndexIterator(opCtx, false);
- auto query = parsedDistinct.getQuery()->getQueryRequest().getFilter();
+ auto query = parsedDistinct.getQuery()->getFindCommand().getFilter();
while (ii->more()) {
const IndexCatalogEntry* ice = ii->next();
const IndexDescriptor* desc = ice->descriptor();
@@ -2043,7 +2045,7 @@ QueryPlannerParams fillOutPlannerParamsForDistinct(OperationContext* opCtx,
}
const CanonicalQuery* canonicalQuery = parsedDistinct.getQuery();
- const BSONObj& hint = canonicalQuery->getQueryRequest().getHint();
+ const BSONObj& hint = canonicalQuery->getFindCommand().getHint();
applyIndexFilters(collection, *canonicalQuery, &plannerParams);
@@ -2083,7 +2085,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorForS
// If there's no query, we can just distinct-scan one of the indices. Not every index in
// plannerParams.indices may be suitable. Refer to getDistinctNodeIndex().
size_t distinctNodeIndex = 0;
- if (!parsedDistinct->getQuery()->getQueryRequest().getFilter().isEmpty() ||
+ if (!parsedDistinct->getQuery()->getFindCommand().getFilter().isEmpty() ||
parsedDistinct->getQuery()->getSortPattern() ||
!getDistinctNodeIndex(
plannerParams.indices, parsedDistinct->getKey(), collator, &distinctNodeIndex)) {
@@ -2204,14 +2206,15 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorWith
size_t plannerOptions) {
const auto& collection = *coll;
- auto qr = std::make_unique<QueryRequest>(cq->getQueryRequest());
- qr->setProj(BSONObj());
+ auto findCommand = std::make_unique<FindCommand>(cq->getFindCommand());
+ findCommand->setProjection(BSONObj());
const boost::intrusive_ptr<ExpressionContext> expCtx;
const ExtensionsCallbackReal extensionsCallback(opCtx, &collection->ns());
auto cqWithoutProjection =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ cq->getExplain(),
expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h
index 21637b03b88..00ed169447c 100644
--- a/src/mongo/db/query/get_executor.h
+++ b/src/mongo/db/query/get_executor.h
@@ -176,7 +176,7 @@ bool turnIxscanIntoDistinctIxscan(QuerySolution* soln,
* A $group stage on a single field behaves similarly to a distinct command. If it has no
* accumulators or only $first accumulators, the $group command only needs to visit one document for
* each distinct value of the grouped-by (_id) field to compute its result. When there is a sort
- * order specified in parsedDistinct->getQuery()->getQueryRequest.getSort(), the DISTINCT_SCAN will
+ * order specified in parsedDistinct->getQuery()->getFindCommand().getSort(), the DISTINCT_SCAN will
* follow that sort order, ensuring that it chooses the correct document from each group to compute
* any $first accumulators.
*
diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp
index 40da9d86e8e..e3ac2411131 100644
--- a/src/mongo/db/query/get_executor_test.cpp
+++ b/src/mongo/db/query/get_executor_test.cpp
@@ -74,11 +74,11 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projStr));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projStr));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/db/query/parsed_distinct.cpp b/src/mongo/db/query/parsed_distinct.cpp
index dc751b3eead..e797f9650c2 100644
--- a/src/mongo/db/query/parsed_distinct.cpp
+++ b/src/mongo/db/query/parsed_distinct.cpp
@@ -37,7 +37,7 @@
#include "mongo/bson/util/bson_extract.h"
#include "mongo/db/query/canonical_query.h"
#include "mongo/db/query/distinct_command_gen.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/idl/idl_parser.h"
#include "mongo/util/str.h"
@@ -171,8 +171,9 @@ StatusWith<BSONObj> ParsedDistinct::asAggregationCommand() const {
BSONObjBuilder aggregationBuilder;
invariant(_query);
- const QueryRequest& qr = _query->getQueryRequest();
- aggregationBuilder.append("aggregate", qr.nss().coll());
+ const FindCommand& findCommand = _query->getFindCommand();
+ aggregationBuilder.append(
+ "aggregate", findCommand.getNamespaceOrUUID().nss().value_or(NamespaceString()).coll());
// Build a pipeline that accomplishes the distinct request. The building code constructs a
// pipeline that looks like this, assuming the distinct is on the key "a.b.c"
@@ -201,9 +202,9 @@ StatusWith<BSONObj> ParsedDistinct::asAggregationCommand() const {
// Any arrays remaining after the $unwinds must have been nested arrays, so in order to match
// the behavior of the distinct() command, we filter them out before the $group.
BSONArrayBuilder pipelineBuilder(aggregationBuilder.subarrayStart("pipeline"));
- if (!qr.getFilter().isEmpty()) {
+ if (!findCommand.getFilter().isEmpty()) {
BSONObjBuilder matchStageBuilder(pipelineBuilder.subobjStart());
- matchStageBuilder.append("$match", qr.getFilter());
+ matchStageBuilder.append("$match", findCommand.getFilter());
matchStageBuilder.doneFast();
}
@@ -225,19 +226,21 @@ StatusWith<BSONObj> ParsedDistinct::asAggregationCommand() const {
groupStageBuilder.doneFast();
pipelineBuilder.doneFast();
- aggregationBuilder.append(kCollationField, qr.getCollation());
+ aggregationBuilder.append(kCollationField, findCommand.getCollation());
- if (qr.getMaxTimeMS() > 0) {
- aggregationBuilder.append(QueryRequest::cmdOptionMaxTimeMS, qr.getMaxTimeMS());
+ int maxTimeMS = findCommand.getMaxTimeMS() ? static_cast<int>(*findCommand.getMaxTimeMS()) : 0;
+ if (maxTimeMS > 0) {
+ aggregationBuilder.append(query_request_helper::cmdOptionMaxTimeMS, maxTimeMS);
}
- if (qr.getReadConcern() && !qr.getReadConcern()->isEmpty()) {
+ if (findCommand.getReadConcern() && !findCommand.getReadConcern()->isEmpty()) {
aggregationBuilder.append(repl::ReadConcernArgs::kReadConcernFieldName,
- *qr.getReadConcern());
+ *findCommand.getReadConcern());
}
- if (!qr.getUnwrappedReadPref().isEmpty()) {
- aggregationBuilder.append(QueryRequest::kUnwrappedReadPrefField, qr.getUnwrappedReadPref());
+ if (!findCommand.getUnwrappedReadPref().isEmpty()) {
+ aggregationBuilder.append(query_request_helper::kUnwrappedReadPrefField,
+ findCommand.getUnwrappedReadPref());
}
// Specify the 'cursor' option so that aggregation uses the cursor interface.
@@ -261,7 +264,7 @@ StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx,
return exceptionToStatus();
}
- auto qr = std::make_unique<QueryRequest>(nss);
+ auto findCommand = std::make_unique<FindCommand>(nss);
if (parsedDistinct.getKey().find('\0') != std::string::npos) {
return Status(ErrorCodes::Error(31032), "Key field cannot contain an embedded null byte");
@@ -269,14 +272,14 @@ StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx,
// 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())));
+ findCommand->setProjection(getDistinctProjection(std::string(parsedDistinct.getKey())));
if (auto query = parsedDistinct.getQuery()) {
- qr->setFilter(query.get());
+ findCommand->setFilter(query.get().getOwned());
}
if (auto collation = parsedDistinct.getCollation()) {
- qr->setCollation(collation.get());
+ findCommand->setCollation(collation.get().getOwned());
}
// The IDL parser above does not handle generic command arguments. Since the underlying query
@@ -289,33 +292,32 @@ StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx,
<< "\" had the wrong type. Expected " << typeName(BSONType::Object)
<< ", found " << typeName(readConcernElt.type()));
}
- qr->setReadConcern(readConcernElt.embeddedObject());
+ findCommand->setReadConcern(readConcernElt.embeddedObject().getOwned());
}
- if (auto queryOptionsElt = cmdObj[QueryRequest::kUnwrappedReadPrefField]) {
+ if (auto queryOptionsElt = cmdObj[query_request_helper::kUnwrappedReadPrefField]) {
if (queryOptionsElt.type() != BSONType::Object) {
return Status(ErrorCodes::TypeMismatch,
str::stream()
- << "\"" << QueryRequest::kUnwrappedReadPrefField
+ << "\"" << query_request_helper::kUnwrappedReadPrefField
<< "\" had the wrong type. Expected " << typeName(BSONType::Object)
<< ", found " << typeName(queryOptionsElt.type()));
}
- qr->setUnwrappedReadPref(queryOptionsElt.embeddedObject());
+ findCommand->setUnwrappedReadPref(queryOptionsElt.embeddedObject().getOwned());
}
- if (auto maxTimeMSElt = cmdObj[QueryRequest::cmdOptionMaxTimeMS]) {
+ if (auto maxTimeMSElt = cmdObj[query_request_helper::cmdOptionMaxTimeMS]) {
auto maxTimeMS = parseMaxTimeMS(maxTimeMSElt);
if (!maxTimeMS.isOK()) {
return maxTimeMS.getStatus();
}
- qr->setMaxTimeMS(static_cast<unsigned int>(maxTimeMS.getValue()));
+ findCommand->setMaxTimeMS(static_cast<unsigned int>(maxTimeMS.getValue()));
}
- qr->setExplain(isExplain);
-
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto cq = CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx,
extensionsCallback,
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -323,7 +325,7 @@ StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx,
return cq.getStatus();
}
- if (cq.getValue()->getQueryRequest().getCollation().isEmpty() && defaultCollator) {
+ if (cq.getValue()->getFindCommand().getCollation().isEmpty() && defaultCollator) {
cq.getValue()->setCollator(defaultCollator->clone());
}
diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp
index f29c2925b6b..6a78e017dee 100644
--- a/src/mongo/db/query/plan_cache.cpp
+++ b/src/mongo/db/query/plan_cache.cpp
@@ -121,7 +121,7 @@ StringBuilder& operator<<(StringBuilder& builder, const PlanCacheKey& key) {
//
bool PlanCache::shouldCacheQuery(const CanonicalQuery& query) {
- const QueryRequest& qr = query.getQueryRequest();
+ const FindCommand& findCommand = query.getFindCommand();
const MatchExpression* expr = query.root();
// Collection scan
@@ -132,19 +132,19 @@ bool PlanCache::shouldCacheQuery(const CanonicalQuery& query) {
}
// Hint provided
- if (!qr.getHint().isEmpty()) {
+ if (!findCommand.getHint().isEmpty()) {
return false;
}
// Min provided
// Min queries are a special case of hinted queries.
- if (!qr.getMin().isEmpty()) {
+ if (!findCommand.getMin().isEmpty()) {
return false;
}
// Max provided
// Similar to min, max queries are a special case of hinted queries.
- if (!qr.getMax().isEmpty()) {
+ if (!findCommand.getMax().isEmpty()) {
return false;
}
@@ -152,12 +152,12 @@ bool PlanCache::shouldCacheQuery(const CanonicalQuery& query) {
// that explain queries don't affect cache state, and it also makes
// sure that we can always generate information regarding rejected plans
// and/or trial period execution of candidate plans.
- if (qr.isExplain()) {
+ if (query.getExplain()) {
return false;
}
// Tailable cursors won't get cached, just turn into collscans.
- if (query.getQueryRequest().isTailable()) {
+ if (query.getFindCommand().getTailable()) {
return false;
}
@@ -204,9 +204,9 @@ std::unique_ptr<PlanCacheEntry> PlanCacheEntry::create(
if (includeDebugInfo) {
// Strip projections on $-prefixed fields, as these are added by internal callers of the
// system and are not considered part of the user projection.
- const QueryRequest& qr = query.getQueryRequest();
+ const FindCommand& findCommand = query.getFindCommand();
BSONObjBuilder projBuilder;
- for (auto elem : qr.getProj()) {
+ for (auto elem : findCommand.getProjection()) {
if (elem.fieldName()[0] == '$') {
continue;
}
@@ -214,8 +214,8 @@ std::unique_ptr<PlanCacheEntry> PlanCacheEntry::create(
}
CreatedFromQuery createdFromQuery{
- qr.getFilter(),
- qr.getSort(),
+ findCommand.getFilter(),
+ findCommand.getSort(),
projBuilder.obj(),
query.getCollator() ? query.getCollator()->getSpec().toBSON() : BSONObj()};
debugInfo.emplace(std::move(createdFromQuery), std::move(decision));
diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp
index 9df05d614bf..6d2bb24bd0a 100644
--- a/src/mongo/db/query/plan_cache_test.cpp
+++ b/src/mongo/db/query/plan_cache_test.cpp
@@ -74,12 +74,13 @@ unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) {
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(queryObj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(queryObj);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -99,15 +100,16 @@ unique_ptr<CanonicalQuery> canonicalize(BSONObj query,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
- qr->setCollation(collation);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ findCommand->setSort(sort);
+ findCommand->setProjection(proj);
+ findCommand->setCollation(collation);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -134,23 +136,24 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projStr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projStr));
if (skip) {
- qr->setSkip(skip);
+ findCommand->setSkip(skip);
}
if (limit) {
- qr->setLimit(limit);
+ findCommand->setLimit(limit);
}
- qr->setHint(fromjson(hintStr));
- qr->setMin(fromjson(minStr));
- qr->setMax(fromjson(maxStr));
+ findCommand->setHint(fromjson(hintStr));
+ findCommand->setMin(fromjson(minStr));
+ findCommand->setMax(fromjson(maxStr));
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -170,24 +173,24 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson(queryStr));
- qr->setSort(fromjson(sortStr));
- qr->setProj(fromjson(projStr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson(queryStr));
+ findCommand->setSort(fromjson(sortStr));
+ findCommand->setProjection(fromjson(projStr));
if (skip) {
- qr->setSkip(skip);
+ findCommand->setSkip(skip);
}
if (limit) {
- qr->setLimit(limit);
+ findCommand->setLimit(limit);
}
- qr->setHint(fromjson(hintStr));
- qr->setMin(fromjson(minStr));
- qr->setMax(fromjson(maxStr));
- qr->setExplain(explain);
+ findCommand->setHint(fromjson(hintStr));
+ findCommand->setMin(fromjson(minStr));
+ findCommand->setMax(fromjson(maxStr));
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ explain,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -487,8 +490,7 @@ TEST(PlanCacheTest, ShouldNotCacheQueryExplain) {
"{}", // min, max
true // explain
));
- const QueryRequest& qr = cq->getQueryRequest();
- ASSERT_TRUE(qr.isExplain());
+ ASSERT_TRUE(cq->getExplain());
assertShouldNotCacheQuery(*cq);
}
@@ -1015,23 +1017,24 @@ protected:
// Clean up any previous state from a call to runQueryFull or runQueryAsCommand.
solns.clear();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ findCommand->setSort(sort);
+ findCommand->setProjection(proj);
if (skip) {
- qr->setSkip(skip);
+ findCommand->setSkip(skip);
}
if (limit) {
- qr->setLimit(limit);
+ findCommand->setLimit(limit);
}
- qr->setHint(hint);
- qr->setMin(minObj);
- qr->setMax(maxObj);
+ findCommand->setHint(hint);
+ findCommand->setMin(minObj);
+ findCommand->setMax(maxObj);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -1049,13 +1052,14 @@ protected:
solns.clear();
const bool isExplain = false;
- std::unique_ptr<QueryRequest> qr(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ std::unique_ptr<FindCommand> findCommand(
+ query_request_helper::makeFromFindCommandForTests(cmdObj));
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -1121,15 +1125,16 @@ protected:
QueryTestServiceContext serviceContext;
auto opCtx = serviceContext.makeOperationContext();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
- qr->setCollation(collation);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ findCommand->setSort(sort);
+ findCommand->setProjection(proj);
+ findCommand->setCollation(collation);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/query/plan_executor_impl.cpp b/src/mongo/db/query/plan_executor_impl.cpp
index 5ebe5455ad3..a5c13f4cf6e 100644
--- a/src/mongo/db/query/plan_executor_impl.cpp
+++ b/src/mongo/db/query/plan_executor_impl.cpp
@@ -150,7 +150,7 @@ PlanExecutorImpl::PlanExecutorImpl(OperationContext* opCtx,
_nss = collection->ns();
} else {
invariant(_cq);
- _nss = _cq->getQueryRequest().nss();
+ _nss = _cq->getFindCommand().getNamespaceOrUUID().nss().value_or(NamespaceString());
}
uassertStatusOK(_pickBestPlan());
diff --git a/src/mongo/db/query/plan_insert_listener.cpp b/src/mongo/db/query/plan_insert_listener.cpp
index b1140df2641..8591004401f 100644
--- a/src/mongo/db/query/plan_insert_listener.cpp
+++ b/src/mongo/db/query/plan_insert_listener.cpp
@@ -45,7 +45,7 @@ MONGO_FAIL_POINT_DEFINE(planExecutorHangWhileYieldedInWaitForInserts);
}
bool shouldListenForInserts(OperationContext* opCtx, CanonicalQuery* cq) {
- return cq && cq->getQueryRequest().isTailableAndAwaitData() &&
+ return cq && cq->getFindCommand().getTailable() && cq->getFindCommand().getAwaitData() &&
awaitDataState(opCtx).shouldWaitForInserts && opCtx->checkForInterruptNoAssert().isOK() &&
awaitDataState(opCtx).waitForInsertsDeadline >
opCtx->getServiceContext()->getPreciseClockSource()->now();
diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp
index 2f66961a084..194110865fd 100644
--- a/src/mongo/db/query/planner_access.cpp
+++ b/src/mongo/db/query/planner_access.cpp
@@ -223,9 +223,9 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::makeCollectionScan(
params.options & QueryPlannerParams::OPLOG_SCAN_WAIT_FOR_VISIBLE;
// If the hint is {$natural: +-1} this changes the direction of the collection scan.
- const BSONObj& hint = query.getQueryRequest().getHint();
+ const BSONObj& hint = query.getFindCommand().getHint();
if (!hint.isEmpty()) {
- BSONElement natural = hint[QueryRequest::kNaturalSortField];
+ BSONElement natural = hint[query_request_helper::kNaturalSortField];
if (natural) {
csn->direction = natural.numberInt() >= 0 ? 1 : -1;
}
@@ -234,13 +234,13 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::makeCollectionScan(
// If the client requested a resume token and we are scanning the oplog, prepare
// the collection scan to return timestamp-based tokens. Otherwise, we should
// return generic RecordId-based tokens.
- if (query.getQueryRequest().getRequestResumeToken()) {
+ if (query.getFindCommand().getRequestResumeToken()) {
csn->shouldTrackLatestOplogTimestamp = query.nss().isOplog();
csn->requestResumeToken = !query.nss().isOplog();
}
// Extract and assign the RecordId from the 'resumeAfter' token, if present.
- const BSONObj& resumeAfterObj = query.getQueryRequest().getResumeAfter();
+ const BSONObj& resumeAfterObj = query.getFindCommand().getResumeAfter();
if (!resumeAfterObj.isEmpty()) {
BSONElement recordIdElem = resumeAfterObj["$recordId"];
switch (recordIdElem.type()) {
@@ -1129,7 +1129,7 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::buildIndexedAnd(
for (size_t i = 0; i < andResult->children.size(); ++i) {
andResult->children[i]->computeProperties();
if (andResult->children[i]->providedSorts().contains(
- query.getQueryRequest().getSort())) {
+ query.getFindCommand().getSort())) {
std::swap(andResult->children[i], andResult->children.back());
break;
}
@@ -1230,7 +1230,7 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::buildIndexedOr(
// If all ixscanNodes can provide the sort, shouldReverseScan is populated with which
// scans to reverse.
shouldReverseScan =
- canProvideSortWithMergeSort(ixscanNodes, query.getQueryRequest().getSort());
+ canProvideSortWithMergeSort(ixscanNodes, query.getFindCommand().getSort());
}
if (!shouldReverseScan.empty()) {
@@ -1244,7 +1244,7 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::buildIndexedOr(
}
auto msn = std::make_unique<MergeSortNode>();
- msn->sort = query.getQueryRequest().getSort();
+ msn->sort = query.getFindCommand().getSort();
msn->addChildren(std::move(ixscanNodes));
orResult = std::move(msn);
} else {
diff --git a/src/mongo/db/query/planner_analysis.cpp b/src/mongo/db/query/planner_analysis.cpp
index f61f7fc3264..a0de5bd01bd 100644
--- a/src/mongo/db/query/planner_analysis.cpp
+++ b/src/mongo/db/query/planner_analysis.cpp
@@ -372,7 +372,7 @@ std::unique_ptr<QuerySolutionNode> addSortKeyGeneratorStageIfNeeded(
const CanonicalQuery& query, bool hasSortStage, std::unique_ptr<QuerySolutionNode> solnRoot) {
if (!hasSortStage && query.metadataDeps()[DocumentMetadataFields::kSortKey]) {
auto keyGenNode = std::make_unique<SortKeyGeneratorNode>();
- keyGenNode->sortSpec = query.getQueryRequest().getSort();
+ keyGenNode->sortSpec = query.getFindCommand().getSort();
keyGenNode->children.push_back(solnRoot.release());
return keyGenNode;
}
@@ -539,8 +539,8 @@ std::unique_ptr<QuerySolutionNode> tryPushdownProjectBeneathSort(
bool canUseSimpleSort(const QuerySolutionNode& solnRoot,
const CanonicalQuery& cq,
const QueryPlannerParams& plannerParams) {
- const bool splitLimitedSortEligible = cq.getQueryRequest().getNToReturn() &&
- !cq.getQueryRequest().isSingleBatch() &&
+ const bool splitLimitedSortEligible = cq.getFindCommand().getNtoreturn() &&
+ !cq.getFindCommand().getSingleBatch() &&
plannerParams.options & QueryPlannerParams::SPLIT_LIMITED_SORT;
// The simple sort stage discards any metadata other than sort key metadata. It can only be used
@@ -622,7 +622,7 @@ bool QueryPlannerAnalysis::explodeForSort(const CanonicalQuery& query,
// Find explodable nodes in the subtree rooted at 'toReplace'.
getExplodableNodes(toReplace, &explodableNodes);
- const BSONObj& desiredSort = query.getQueryRequest().getSort();
+ const BSONObj& desiredSort = query.getFindCommand().getSort();
// How many scan leaves will result from our expansion?
size_t totalNumScans = 0;
@@ -764,8 +764,8 @@ QuerySolutionNode* QueryPlannerAnalysis::analyzeSort(const CanonicalQuery& query
bool* blockingSortOut) {
*blockingSortOut = false;
- const QueryRequest& qr = query.getQueryRequest();
- const BSONObj& sortObj = qr.getSort();
+ const FindCommand& findCommand = query.getFindCommand();
+ const BSONObj& sortObj = findCommand.getSort();
if (sortObj.isEmpty()) {
return solnRoot;
@@ -776,7 +776,7 @@ QuerySolutionNode* QueryPlannerAnalysis::analyzeSort(const CanonicalQuery& query
// If the sort is $natural, we ignore it, assuming that the caller has detected that and
// outputted a collscan to satisfy the desired order.
- if (sortObj[QueryRequest::kNaturalSortField]) {
+ if (sortObj[query_request_helper::kNaturalSortField]) {
return solnRoot;
}
@@ -838,19 +838,19 @@ QuerySolutionNode* QueryPlannerAnalysis::analyzeSort(const CanonicalQuery& query
// When setting the limit on the sort, we need to consider both
// the limit N and skip count M. The sort should return an ordered list
// N + M items so that the skip stage can discard the first M results.
- if (qr.getLimit()) {
+ if (findCommand.getLimit()) {
// We have a true limit. The limit can be combined with the SORT stage.
- sortNodeRaw->limit =
- static_cast<size_t>(*qr.getLimit()) + static_cast<size_t>(qr.getSkip().value_or(0));
- } else if (qr.getNToReturn()) {
+ sortNodeRaw->limit = static_cast<size_t>(*findCommand.getLimit()) +
+ static_cast<size_t>(findCommand.getSkip().value_or(0));
+ } else if (findCommand.getNtoreturn()) {
// We have an ntoreturn specified by an OP_QUERY style find. This is used
// by clients to mean both batchSize and limit.
//
// Overflow here would be bad and could cause a nonsense limit. Cast
// skip and limit values to unsigned ints to make sure that the
// sum is never stored as signed. (See SERVER-13537).
- sortNodeRaw->limit =
- static_cast<size_t>(*qr.getNToReturn()) + static_cast<size_t>(qr.getSkip().value_or(0));
+ sortNodeRaw->limit = static_cast<size_t>(*findCommand.getNtoreturn()) +
+ static_cast<size_t>(findCommand.getSkip().value_or(0));
// This is a SORT with a limit. The wire protocol has a single quantity called "numToReturn"
// which could mean either limit or batchSize. We have no idea what the client intended.
@@ -876,7 +876,8 @@ QuerySolutionNode* QueryPlannerAnalysis::analyzeSort(const CanonicalQuery& query
//
// Not allowed for geo or text, because we assume elsewhere that those stages appear just
// once.
- if (!qr.isSingleBatch() && params.options & QueryPlannerParams::SPLIT_LIMITED_SORT &&
+ if (!findCommand.getSingleBatch() &&
+ params.options & QueryPlannerParams::SPLIT_LIMITED_SORT &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::TEXT) &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO) &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR)) {
@@ -973,17 +974,17 @@ std::unique_ptr<QuerySolution> QueryPlannerAnalysis::analyzeDataAccess(
bool hasAndHashStage = solnRoot->hasNode(STAGE_AND_HASH);
soln->hasBlockingStage = hasSortStage || hasAndHashStage;
- const QueryRequest& qr = query.getQueryRequest();
+ const FindCommand& findCommand = query.getFindCommand();
- if (qr.getSkip()) {
+ if (findCommand.getSkip()) {
auto skip = std::make_unique<SkipNode>();
- skip->skip = *qr.getSkip();
+ skip->skip = *findCommand.getSkip();
skip->children.push_back(solnRoot.release());
solnRoot = std::move(skip);
}
// Project the results.
- if (qr.returnKey()) {
+ if (findCommand.getReturnKey()) {
// We don't need a projection stage if returnKey was requested since the intended behavior
// is that the projection is ignored when returnKey is specified.
solnRoot = std::make_unique<ReturnKeyNode>(
@@ -1012,16 +1013,16 @@ std::unique_ptr<QuerySolution> QueryPlannerAnalysis::analyzeDataAccess(
if (!hasSortStage) {
// We don't have a sort stage. This means that, if there is a limit, we will have
// to enforce it ourselves since it's not handled inside SORT.
- if (qr.getLimit()) {
+ if (findCommand.getLimit()) {
LimitNode* limit = new LimitNode();
- limit->limit = *qr.getLimit();
+ limit->limit = *findCommand.getLimit();
limit->children.push_back(solnRoot.release());
solnRoot.reset(limit);
- } else if (qr.getNToReturn() && qr.isSingleBatch()) {
+ } else if (findCommand.getNtoreturn() && findCommand.getSingleBatch()) {
// We have a "legacy limit", i.e. a negative ntoreturn value from an OP_QUERY style
// find.
LimitNode* limit = new LimitNode();
- limit->limit = *qr.getNToReturn();
+ limit->limit = *findCommand.getNtoreturn();
limit->children.push_back(solnRoot.release());
solnRoot.reset(limit);
}
diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp
index 70f62ecc418..fb902758eb5 100644
--- a/src/mongo/db/query/query_planner.cpp
+++ b/src/mongo/db/query/query_planner.cpp
@@ -341,7 +341,7 @@ std::unique_ptr<QuerySolution> buildWholeIXSoln(const IndexEntry& index,
}
bool providesSort(const CanonicalQuery& query, const BSONObj& kp) {
- return query.getQueryRequest().getSort().isPrefixOf(kp, SimpleBSONElementComparator::kInstance);
+ return query.getFindCommand().getSort().isPrefixOf(kp, SimpleBSONElementComparator::kInstance);
}
StatusWith<std::unique_ptr<PlanCacheIndexTree>> QueryPlanner::cacheDataFromTaggedTree(
@@ -609,7 +609,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan(
}
const bool canTableScan = !(params.options & QueryPlannerParams::NO_TABLE_SCAN);
- const bool isTailable = query.getQueryRequest().isTailable();
+ const bool isTailable = query.getFindCommand().getTailable();
// If the query requests a tailable cursor, the only solution is a collscan + filter with
// tailable set on the collscan.
@@ -632,16 +632,16 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan(
// The hint can be {$natural: +/-1}. If this happens, output a collscan. We expect any $natural
// sort to have been normalized to a $natural hint upstream.
- if (!query.getQueryRequest().getHint().isEmpty()) {
- const BSONObj& hintObj = query.getQueryRequest().getHint();
- if (hintObj[QueryRequest::kNaturalSortField]) {
+ if (!query.getFindCommand().getHint().isEmpty()) {
+ const BSONObj& hintObj = query.getFindCommand().getHint();
+ if (hintObj[query_request_helper::kNaturalSortField]) {
LOGV2_DEBUG(20969, 5, "Forcing a table scan due to hinted $natural");
if (!canTableScan) {
return Status(ErrorCodes::NoQueryExecutionPlans,
"hint $natural is not allowed, because 'notablescan' is enabled");
}
- if (!query.getQueryRequest().getMin().isEmpty() ||
- !query.getQueryRequest().getMax().isEmpty()) {
+ if (!query.getFindCommand().getMin().isEmpty() ||
+ !query.getFindCommand().getMax().isEmpty()) {
return Status(ErrorCodes::NoQueryExecutionPlans,
"min and max are incompatible with $natural");
}
@@ -661,7 +661,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan(
// requested in the query.
BSONObj hintedIndex;
if (!params.indexFiltersApplied) {
- hintedIndex = query.getQueryRequest().getHint();
+ hintedIndex = query.getFindCommand().getHint();
}
// Either the list of indices passed in by the caller, or the list of indices filtered according
@@ -717,16 +717,15 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan(
// Deal with the .min() and .max() query options. If either exist we can only use an index
// that matches the object inside.
- if (!query.getQueryRequest().getMin().isEmpty() ||
- !query.getQueryRequest().getMax().isEmpty()) {
+ if (!query.getFindCommand().getMin().isEmpty() || !query.getFindCommand().getMax().isEmpty()) {
if (!hintedIndexEntry) {
return Status(ErrorCodes::Error(51173),
"When using min()/max() a hint of which index to use must be provided");
}
- BSONObj minObj = query.getQueryRequest().getMin();
- BSONObj maxObj = query.getQueryRequest().getMax();
+ BSONObj minObj = query.getFindCommand().getMin();
+ BSONObj maxObj = query.getFindCommand().getMax();
if ((!minObj.isEmpty() &&
!indexCompatibleMaxMin(minObj, query.getCollator(), *hintedIndexEntry)) ||
@@ -788,7 +787,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan(
//
// TEXT and GEO_NEAR are special because they require the use of a text/geo index in order
// to be evaluated correctly. Stripping these "mandatory assignments" is therefore invalid.
- if (query.getQueryRequest().getProj().isEmpty() &&
+ if (query.getFindCommand().getProjection().isEmpty() &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR) &&
!QueryPlannerCommon::hasNode(query.root(), MatchExpression::TEXT)) {
QueryPlannerIXSelect::stripUnneededAssignments(query.root(), relevantIndices);
diff --git a/src/mongo/db/query/query_planner_operator_test.cpp b/src/mongo/db/query/query_planner_operator_test.cpp
index 2acb55d5687..017fae0a40c 100644
--- a/src/mongo/db/query/query_planner_operator_test.cpp
+++ b/src/mongo/db/query/query_planner_operator_test.cpp
@@ -802,7 +802,7 @@ TEST_F(QueryPlannerTest, CompoundIndexWithEqualityPredicatesProvidesSort) {
//
TEST_F(QueryPlannerTest, SortLimit) {
- // Negative limit indicates hard limit - see query_request.cpp
+ // Negative limit indicates hard limit - see query_request_helper.cpp
runQuerySortProjSkipNToReturn(BSONObj(), fromjson("{a: 1}"), BSONObj(), 0, -3);
assertNumSolutions(1U);
assertSolutionExists(
diff --git a/src/mongo/db/query/query_planner_options_test.cpp b/src/mongo/db/query/query_planner_options_test.cpp
index 460433db511..3ff3392fcae 100644
--- a/src/mongo/db/query/query_planner_options_test.cpp
+++ b/src/mongo/db/query/query_planner_options_test.cpp
@@ -828,9 +828,9 @@ TEST_F(QueryPlannerTest, CacheDataFromTaggedTreeFailsOnBadInput) {
// No relevant index matching the index tag.
relevantIndices.push_back(buildSimpleIndexEntry(BSON("a" << 1), "a_1"));
- auto qr = std::make_unique<QueryRequest>(NamespaceString("test.collection"));
- qr->setFilter(BSON("a" << 3));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString("test.collection"));
+ findCommand->setFilter(BSON("a" << 3));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue());
scopedCq->root()->setTag(new IndexTag(1));
@@ -842,9 +842,9 @@ TEST_F(QueryPlannerTest, CacheDataFromTaggedTreeFailsOnBadInput) {
TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) {
const NamespaceString nss("test.collection");
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 3));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 3));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue());
@@ -871,7 +871,7 @@ TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) {
ASSERT_OK(s);
// Regenerate canonical query in order to clear tags.
- auto newQR = std::make_unique<QueryRequest>(nss);
+ auto newQR = std::make_unique<FindCommand>(nss);
newQR->setFilter(BSON("a" << 3));
statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(newQR));
ASSERT_OK(statusWithCQ.getStatus());
diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp
index 520544baedc..1a222b2e91c 100644
--- a/src/mongo/db/query/query_planner_test_fixture.cpp
+++ b/src/mongo/db/query/query_planner_test_fixture.cpp
@@ -321,27 +321,28 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query,
const BSONObj& maxObj) {
clearState();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ findCommand->setSort(sort);
+ findCommand->setProjection(proj);
if (skip) {
- qr->setSkip(skip);
+ findCommand->setSkip(skip);
}
if (ntoreturn) {
if (ntoreturn < 0) {
ASSERT_NE(ntoreturn, std::numeric_limits<long long>::min());
ntoreturn = -ntoreturn;
- qr->setSingleBatchField(true);
+ findCommand->setSingleBatch(true);
}
- qr->setNToReturn(ntoreturn);
+ findCommand->setNtoreturn(ntoreturn);
}
- qr->setHint(hint);
- qr->setMin(minObj);
- qr->setMax(maxObj);
+ findCommand->setHint(hint);
+ findCommand->setMin(minObj);
+ findCommand->setMax(maxObj);
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -401,27 +402,28 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query,
const BSONObj& maxObj) {
clearState();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- qr->setSort(sort);
- qr->setProj(proj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ findCommand->setSort(sort);
+ findCommand->setProjection(proj);
if (skip) {
- qr->setSkip(skip);
+ findCommand->setSkip(skip);
}
if (ntoreturn) {
if (ntoreturn < 0) {
ASSERT_NE(ntoreturn, std::numeric_limits<long long>::min());
ntoreturn = -ntoreturn;
- qr->setSingleBatchField(true);
+ findCommand->setSingleBatch(true);
}
- qr->setNToReturn(ntoreturn);
+ findCommand->setNtoreturn(ntoreturn);
}
- qr->setHint(hint);
- qr->setMin(minObj);
- qr->setMax(maxObj);
+ findCommand->setHint(hint);
+ findCommand->setMin(minObj);
+ findCommand->setMax(maxObj);
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -443,12 +445,13 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) {
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody(nss.db(), cmdObj).body;
- std::unique_ptr<QueryRequest> qr(
- QueryRequest::makeFromFindCommandForTests(cmd, isExplain, nss));
+ std::unique_ptr<FindCommand> findCommand(
+ query_request_helper::makeFromFindCommandForTests(cmd, nss));
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -469,12 +472,13 @@ void QueryPlannerTest::runInvalidQueryAsCommand(const BSONObj& cmdObj) {
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody(nss.db(), cmdObj).body;
- std::unique_ptr<QueryRequest> qr(
- QueryRequest::makeFromFindCommandForTests(cmd, isExplain, nss));
+ std::unique_ptr<FindCommand> findCommand(
+ query_request_helper::makeFromFindCommandForTests(cmd, nss));
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx.get(),
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/db/query/query_request.h b/src/mongo/db/query/query_request.h
deleted file mode 100644
index bb06302c612..00000000000
--- a/src/mongo/db/query/query_request.h
+++ /dev/null
@@ -1,524 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <boost/optional.hpp>
-#include <string>
-
-#include "mongo/db/catalog/collection_options.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/db/pipeline/legacy_runtime_constants_gen.h"
-#include "mongo/db/query/find_command_gen.h"
-#include "mongo/db/query/tailable_mode.h"
-
-namespace mongo {
-
-class QueryMessage;
-class Status;
-template <typename T>
-class StatusWith;
-
-/**
- * Parses the QueryMessage or find command received from the user and makes the various fields
- * more easily accessible.
- */
-class QueryRequest {
-public:
- static constexpr auto kMaxTimeMSOpOnlyField = "maxTimeMSOpOnly";
-
- // Field names for sorting options.
- static constexpr auto kNaturalSortField = "$natural";
-
- static constexpr auto kShardVersionField = "shardVersion";
-
- explicit QueryRequest(NamespaceStringOrUUID nss, bool preferNssForSerialization = true);
- explicit QueryRequest(FindCommand findCommand);
-
- /**
- * Returns a non-OK status if any property of the QR has a bad value (e.g. a negative skip
- * value) or if there is a bad combination of options (e.g. awaitData is illegal without
- * tailable).
- */
- Status validate() const;
-
- /**
- * Parses a find command object, 'cmdObj'. Caller must indicate whether or not this lite
- * parsed query is an explained query or not via 'isExplain'. Accepts a NSS with which
- * to initialize the QueryRequest if there is no UUID in cmdObj.
- *
- * Returns a heap allocated QueryRequest on success or an error if 'cmdObj' is not well
- * formed.
- */
- static std::unique_ptr<QueryRequest> makeFromFindCommand(const BSONObj& cmdObj,
- bool isExplain,
- boost::optional<NamespaceString> nss,
- bool apiStrict);
-
- static std::unique_ptr<QueryRequest> makeFromFindCommandForTests(
- const BSONObj& cmdObj,
- bool isExplain,
- boost::optional<NamespaceString> nss = boost::none,
- bool apiStrict = false);
-
- /**
- * If _uuid exists for this QueryRequest, update the value of _nss.
- */
- void refreshNSS(const NamespaceString& nss);
-
- void setNSS(const NamespaceString& nss) {
- auto& nssOrUuid = _findCommand.getNamespaceOrUUID();
- nssOrUuid.setNss(nss);
- }
-
- /**
- * Converts this QR into a find command.
- * The withUuid variants make a UUID-based find command instead of a namespace-based ones.
- */
- BSONObj asFindCommand() const;
-
- /**
- * Common code for UUID and namespace-based find commands.
- */
- void asFindCommand(BSONObjBuilder* cmdBuilder) const;
-
- /**
- * Converts this QR into an aggregation using $match. If this QR has options that cannot be
- * satisfied by aggregation, a non-OK status is returned and 'cmdBuilder' is not modified.
- */
- StatusWith<BSONObj> asAggregationCommand() const;
-
- /**
- * Helper function to identify text search sort key
- * Example: {a: {$meta: "textScore"}}
- */
- static bool isTextScoreMeta(BSONElement elt);
-
- // Read preference is attached to commands in "wrapped" form, e.g.
- // { $query: { <cmd>: ... } , <kWrappedReadPrefField>: { ... } }
- //
- // However, mongos internally "unwraps" the read preference and adds it as a parameter to the
- // command, e.g.
- // { <cmd>: ... , <kUnwrappedReadPrefField>: { <kWrappedReadPrefField>: { ... } } }
- static constexpr auto kWrappedReadPrefField = "$readPreference";
- static constexpr auto kUnwrappedReadPrefField = "$queryOptions";
-
- // Names of the maxTimeMS command and query option.
- // Char arrays because they are used in static initialization.
- static constexpr auto cmdOptionMaxTimeMS = "maxTimeMS";
- static constexpr auto queryOptionMaxTimeMS = "$maxTimeMS";
-
- // Names of the $meta projection values.
- static constexpr auto metaGeoNearDistance = "geoNearDistance";
- static constexpr auto metaGeoNearPoint = "geoNearPoint";
- static constexpr auto metaRecordId = "recordId";
- static constexpr auto metaSortKey = "sortKey";
- static constexpr auto metaTextScore = "textScore";
-
- // Allow using disk during the find command.
- static constexpr auto kAllowDiskUseField = "allowDiskUse";
-
- // A constant by which 'maxTimeMSOpOnly' values are allowed to exceed the max allowed value for
- // 'maxTimeMS'. This is because mongod and mongos server processes add a small amount to the
- // 'maxTimeMS' value they are given before passing it on as 'maxTimeMSOpOnly', to allow for
- // clock precision.
- static constexpr auto kMaxTimeMSOpOnlyMaxPadding = 100LL;
-
- const NamespaceString& nss() const {
- if (_findCommand.getNamespaceOrUUID().nss()) {
- return *_findCommand.getNamespaceOrUUID().nss();
- } else {
- static NamespaceString nss = NamespaceString();
- return nss;
- }
- }
-
- boost::optional<UUID> uuid() const {
- return _findCommand.getNamespaceOrUUID().uuid();
- }
-
- const BSONObj& getFilter() const {
- return _findCommand.getFilter();
- }
-
- void setFilter(BSONObj filter) {
- _findCommand.setFilter(filter.getOwned());
- }
-
- const BSONObj& getProj() const {
- return _findCommand.getProjection();
- }
-
- void setProj(BSONObj proj) {
- _findCommand.setProjection(proj.getOwned());
- }
-
- const BSONObj& getSort() const {
- return _findCommand.getSort();
- }
-
- void setSort(BSONObj sort) {
- _findCommand.setSort(sort.getOwned());
- }
-
- const BSONObj& getHint() const {
- return _findCommand.getHint();
- }
-
- void setHint(BSONObj hint) {
- _findCommand.setHint(hint.getOwned());
- }
-
- boost::optional<BSONObj> getReadConcern() const {
- return _findCommand.getReadConcern();
- }
-
- void setReadConcern(BSONObj readConcern) {
- _findCommand.setReadConcern(readConcern.getOwned());
- }
-
- const BSONObj& getCollation() const {
- return _findCommand.getCollation();
- }
-
- void setCollation(BSONObj collation) {
- _findCommand.setCollation(collation.getOwned());
- }
-
- static constexpr auto kDefaultBatchSize = 101ll;
-
- boost::optional<std::int64_t> getSkip() const {
- return _findCommand.getSkip();
- }
-
- void setSkip(boost::optional<std::int64_t> skip) {
- _findCommand.setSkip(skip);
- }
-
- boost::optional<std::int64_t> getLimit() const {
- return _findCommand.getLimit();
- }
-
- void setLimit(boost::optional<std::int64_t> limit) {
- _findCommand.setLimit(limit);
- }
-
- boost::optional<std::int64_t> getBatchSize() const {
- return _findCommand.getBatchSize();
- }
-
- void setBatchSize(boost::optional<std::int64_t> batchSize) {
- _findCommand.setBatchSize(batchSize);
- }
-
- boost::optional<std::int64_t> getNToReturn() const {
- return _findCommand.getNtoreturn();
- }
-
- void setNToReturn(boost::optional<std::int64_t> ntoreturn) {
- _findCommand.setNtoreturn(ntoreturn);
- }
-
- /**
- * Returns batchSize or ntoreturn value if either is set. If neither is set,
- * returns boost::none.
- */
- boost::optional<std::int64_t> getEffectiveBatchSize() const;
-
- bool isSingleBatch() const {
- return _findCommand.getSingleBatch();
- }
-
- void setSingleBatchField(bool singleBatch) {
- _findCommand.setSingleBatch(singleBatch);
- }
-
- bool allowDiskUse() const {
- return _findCommand.getAllowDiskUse();
- }
-
- void setAllowDiskUse(bool allowDiskUse) {
- _findCommand.setAllowDiskUse(allowDiskUse);
- }
-
- bool isExplain() const {
- return _explain;
- }
-
- void setExplain(bool explain) {
- _explain = explain;
- }
-
- const BSONObj& getUnwrappedReadPref() const {
- return _findCommand.getUnwrappedReadPref();
- }
-
- void setUnwrappedReadPref(BSONObj unwrappedReadPref) {
- _findCommand.setUnwrappedReadPref(unwrappedReadPref.getOwned());
- }
-
- int getMaxTimeMS() const {
- return _findCommand.getMaxTimeMS() ? static_cast<int>(*_findCommand.getMaxTimeMS()) : 0;
- }
-
- void setMaxTimeMS(int maxTimeMS) {
- _findCommand.setMaxTimeMS(maxTimeMS);
- }
-
- const BSONObj& getMin() const {
- return _findCommand.getMin();
- }
-
- void setMin(BSONObj min) {
- _findCommand.setMin(min.getOwned());
- }
-
- const BSONObj& getMax() const {
- return _findCommand.getMax();
- }
-
- void setMax(BSONObj max) {
- _findCommand.setMax(max.getOwned());
- }
-
- bool returnKey() const {
- return _findCommand.getReturnKey();
- }
-
- void setReturnKey(bool returnKey) {
- _findCommand.setReturnKey(returnKey);
- }
-
- bool showRecordId() const {
- return _findCommand.getShowRecordId();
- }
-
- void setShowRecordId(bool showRecordId) {
- _findCommand.setShowRecordId(showRecordId);
- }
-
- bool hasReadPref() const {
- return _hasReadPref;
- }
-
- void setHasReadPref(bool hasReadPref) {
- _hasReadPref = hasReadPref;
- }
-
- bool isTailable() const {
- return _tailableMode == TailableModeEnum::kTailable ||
- _tailableMode == TailableModeEnum::kTailableAndAwaitData;
- }
-
- bool isTailableAndAwaitData() const {
- return _tailableMode == TailableModeEnum::kTailableAndAwaitData;
- }
-
- void setTailableMode(TailableModeEnum tailableMode) {
- _tailableMode = tailableMode;
- if (_tailableMode == TailableModeEnum::kTailableAndAwaitData) {
- _findCommand.setAwaitData(true);
- _findCommand.setTailable(true);
- } else if (_tailableMode == TailableModeEnum::kTailable) {
- _findCommand.setTailable(true);
- }
- }
-
- TailableModeEnum getTailableMode() const {
- return _tailableMode;
- }
-
- void setLegacyRuntimeConstants(LegacyRuntimeConstants runtimeConstants) {
- _findCommand.setLegacyRuntimeConstants(std::move(runtimeConstants));
- }
-
- const boost::optional<LegacyRuntimeConstants>& getLegacyRuntimeConstants() const {
- return _findCommand.getLegacyRuntimeConstants();
- }
-
- bool getTailable() const {
- return _findCommand.getTailable();
- }
-
- bool getAwaitData() const {
- return _findCommand.getAwaitData();
- }
-
- void setLetParameters(BSONObj letParams) {
- _findCommand.setLet(std::move(letParams));
- }
-
- const boost::optional<BSONObj>& getLetParameters() const {
- return _findCommand.getLet();
- }
-
- bool isSlaveOk() const {
- return _slaveOk;
- }
-
- void setSlaveOk(bool slaveOk) {
- _slaveOk = slaveOk;
- }
-
- bool isNoCursorTimeout() const {
- return _findCommand.getNoCursorTimeout();
- }
-
- void setNoCursorTimeout(bool noCursorTimeout) {
- _findCommand.setNoCursorTimeout(noCursorTimeout);
- }
-
- bool isExhaust() const {
- return _exhaust;
- }
-
- void setExhaust(bool exhaust) {
- _exhaust = exhaust;
- }
-
- bool isAllowPartialResults() const {
- return _findCommand.getAllowPartialResults();
- }
-
- void setAllowPartialResults(bool allowPartialResults) {
- _findCommand.setAllowPartialResults(allowPartialResults);
- }
-
- boost::optional<std::int64_t> getReplicationTerm() const {
- return _findCommand.getTerm();
- }
-
- void setReplicationTerm(boost::optional<std::int64_t> replicationTerm) {
- _findCommand.setTerm(replicationTerm);
- }
-
- bool isReadOnce() const {
- return _findCommand.getReadOnce();
- }
-
- void setReadOnce(bool readOnce) {
- _findCommand.setReadOnce(readOnce);
- }
-
- void setAllowSpeculativeMajorityRead(bool allowSpeculativeMajorityRead) {
- _findCommand.setAllowSpeculativeMajorityRead(allowSpeculativeMajorityRead);
- }
-
- bool allowSpeculativeMajorityRead() const {
- return _findCommand.getAllowSpeculativeMajorityRead();
- }
-
- bool getRequestResumeToken() const {
- return _findCommand.getRequestResumeToken();
- }
-
- void setRequestResumeToken(bool requestResumeToken) {
- _findCommand.setRequestResumeToken(requestResumeToken);
- }
-
- const BSONObj& getResumeAfter() const {
- return _findCommand.getResumeAfter();
- }
-
- void setResumeAfter(BSONObj resumeAfter) {
- _findCommand.setResumeAfter(resumeAfter.getOwned());
- }
-
- /**
- * Return options as a bit vector.
- */
- int getOptions() const;
-
- //
- // Old parsing code: SOON TO BE DEPRECATED.
- //
-
- /**
- * Parse the provided QueryMessage and return a heap constructed QueryRequest, which
- * represents it or an error.
- */
- static StatusWith<std::unique_ptr<QueryRequest>> fromLegacyQueryMessage(const QueryMessage& qm);
-
- /**
- * Parse the provided legacy query object and parameters to construct a QueryRequest.
- */
- static StatusWith<std::unique_ptr<QueryRequest>> fromLegacyQuery(NamespaceStringOrUUID nsOrUuid,
- const BSONObj& queryObj,
- const BSONObj& proj,
- int ntoskip,
- int ntoreturn,
- int queryOptions);
-
-private:
- static StatusWith<std::unique_ptr<QueryRequest>> parseFromFindCommand(
- std::unique_ptr<QueryRequest> qr, const BSONObj& cmdObj, bool isExplain);
- Status init(int ntoskip,
- int ntoreturn,
- int queryOptions,
- const BSONObj& queryObj,
- const BSONObj& proj,
- bool fromQueryMessage);
-
- Status initFullQuery(const BSONObj& top);
-
- /**
- * Updates the projection object with a $meta projection for the showRecordId option.
- */
- void addShowRecordIdMetaProj();
-
- /**
- * Initializes options based on the value of the 'options' bit vector.
- *
- * This contains flags such as tailable, exhaust, and noCursorTimeout.
- */
- void initFromInt(int options);
-
- /**
- * Add the meta projection to this object if needed.
- */
- void addMetaProjection();
-
- // TODO SERVER-53060: This additional nesting can be avoided if we move the below fields
- // (_explain, _tailableMode, etc.) into the CanonicalQuery class.
- FindCommand _findCommand;
-
- bool _explain = false;
-
- // Options that can be specified in the OP_QUERY 'flags' header.
- TailableModeEnum _tailableMode = TailableModeEnum::kNormal;
- bool _slaveOk = false;
- bool _exhaust = false;
-
- // Parameters used only by the legacy query request.
- bool _hasReadPref = false;
-};
-
-} // namespace mongo
diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request_helper.cpp
index a823d734085..ec12a47c821 100644
--- a/src/mongo/db/query/query_request.cpp
+++ b/src/mongo/db/query/query_request_helper.cpp
@@ -29,193 +29,361 @@
#include "mongo/platform/basic.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include <memory>
#include "mongo/base/status.h"
#include "mongo/base/status_with.h"
#include "mongo/bson/simple_bsonobj_comparator.h"
-#include "mongo/db/catalog/collection_catalog.h"
-#include "mongo/db/commands.h"
#include "mongo/db/dbmessage.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/db/repl/read_concern_args.h"
-#include "mongo/idl/command_generic_argument.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/util/stacktrace.h"
-#include "mongo/util/str.h"
namespace mongo {
-QueryRequest::QueryRequest(NamespaceStringOrUUID nssOrUuid, bool preferNssForSerialization)
- : _findCommand(std::move(nssOrUuid)) {
- if (preferNssForSerialization) {
- _findCommand.getNamespaceOrUUID().preferNssForSerialization();
+namespace query_request_helper {
+namespace {
+
+/**
+ * Initializes options based on the value of the 'options' bit vector.
+ *
+ * This contains flags such as tailable, exhaust, and noCursorTimeout.
+ */
+void initFromInt(int options, FindCommand* findCommand) {
+ bool tailable = (options & QueryOption_CursorTailable) != 0;
+ bool awaitData = (options & QueryOption_AwaitData) != 0;
+ if (awaitData) {
+ findCommand->setAwaitData(true);
+ }
+ if (tailable) {
+ findCommand->setTailable(true);
+ }
+
+ if ((options & QueryOption_NoCursorTimeout) != 0) {
+ findCommand->setNoCursorTimeout(true);
+ }
+ if ((options & QueryOption_PartialResults) != 0) {
+ findCommand->setAllowPartialResults(true);
}
}
-QueryRequest::QueryRequest(FindCommand findCommand) : _findCommand(std::move(findCommand)) {
- _findCommand.getNamespaceOrUUID().preferNssForSerialization();
+
+/**
+ * Updates the projection object with a $meta projection for the showRecordId option.
+ */
+void addShowRecordIdMetaProj(FindCommand* findCommand) {
+ if (findCommand->getProjection()["$recordId"]) {
+ // There's already some projection on $recordId. Don't overwrite it.
+ return;
+ }
+
+ BSONObjBuilder projBob;
+ projBob.appendElements(findCommand->getProjection());
+ BSONObj metaRecordId = BSON("$recordId" << BSON("$meta" << query_request_helper::metaRecordId));
+ projBob.append(metaRecordId.firstElement());
+ findCommand->setProjection(projBob.obj());
}
-void QueryRequest::refreshNSS(const NamespaceString& nss) {
- if (_findCommand.getNamespaceOrUUID().uuid()) {
- auto& nssOrUUID = _findCommand.getNamespaceOrUUID();
- nssOrUUID.setNss(nss);
+/**
+ * Add the meta projection to this object if needed.
+ */
+void addMetaProjection(FindCommand* findCommand) {
+ if (findCommand->getShowRecordId()) {
+ addShowRecordIdMetaProj(findCommand);
}
- invariant(_findCommand.getNamespaceOrUUID().nss());
}
-// static
-std::unique_ptr<QueryRequest> QueryRequest::makeFromFindCommand(
- const BSONObj& cmdObj, bool isExplain, boost::optional<NamespaceString> nss, bool apiStrict) {
+Status initFullQuery(const BSONObj& top, FindCommand* findCommand, bool* explain) {
+ BSONObjIterator i(top);
- auto qr = std::make_unique<QueryRequest>(
- FindCommand::parse(IDLParserErrorContext("FindCommand", apiStrict), cmdObj));
+ while (i.more()) {
+ BSONElement e = i.next();
+ StringData name = e.fieldNameStringData();
- // If there is an explicit namespace specified overwite it.
- if (nss) {
- qr->setNSS(*nss);
- }
+ if (name == "$orderby" || name == "orderby") {
+ if (Object == e.type()) {
+ findCommand->setSort(e.embeddedObject().getOwned());
+ } else if (Array == e.type()) {
+ findCommand->setSort(e.embeddedObject());
- qr->_tailableMode =
- uassertStatusOK(tailableModeFromBools(qr->getTailable(), qr->getAwaitData()));
+ // TODO: Is this ever used? I don't think so.
+ // Quote:
+ // This is for languages whose "objects" are not well ordered (JSON is well
+ // ordered).
+ // [ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
+ // note: this is slow, but that is ok as order will have very few pieces
+ BSONObjBuilder b;
+ char p[2] = "0";
- qr->_explain = isExplain;
- qr->addMetaProjection();
+ while (1) {
+ BSONObj j = findCommand->getSort().getObjectField(p);
+ if (j.isEmpty()) {
+ break;
+ }
+ BSONElement e = j.firstElement();
+ if (e.eoo()) {
+ return Status(ErrorCodes::BadValue, "bad order array");
+ }
+ if (!e.isNumber()) {
+ return Status(ErrorCodes::BadValue, "bad order array [2]");
+ }
+ b.append(e);
+ (*p)++;
+ if (!(*p <= '9')) {
+ return Status(ErrorCodes::BadValue, "too many ordering elements");
+ }
+ }
- if (qr->getSkip() && *qr->getSkip() == 0) {
- qr->setSkip(boost::none);
- }
- if (qr->getLimit() && *qr->getLimit() == 0) {
- qr->setLimit(boost::none);
+ findCommand->setSort(b.obj());
+ } else {
+ return Status(ErrorCodes::BadValue, "sort must be object or array");
+ }
+ } else if (name.startsWith("$")) {
+ name = name.substr(1); // chop first char
+ if (name == "explain") {
+ // Won't throw.
+ *explain = e.trueValue();
+ } else if (name == "min") {
+ if (!e.isABSONObj()) {
+ return Status(ErrorCodes::BadValue, "$min must be a BSONObj");
+ }
+ findCommand->setMin(e.embeddedObject().getOwned());
+ } else if (name == "max") {
+ if (!e.isABSONObj()) {
+ return Status(ErrorCodes::BadValue, "$max must be a BSONObj");
+ }
+ findCommand->setMax(e.embeddedObject().getOwned());
+ } else if (name == "hint") {
+ if (e.isABSONObj()) {
+ findCommand->setHint(e.embeddedObject().getOwned());
+ } else if (String == e.type()) {
+ findCommand->setHint(e.wrap());
+ } else {
+ return Status(ErrorCodes::BadValue,
+ "$hint must be either a string or nested object");
+ }
+ } else if (name == "returnKey") {
+ // Won't throw.
+ if (e.trueValue()) {
+ findCommand->setReturnKey(true);
+ }
+ } else if (name == "showDiskLoc") {
+ // Won't throw.
+ if (e.trueValue()) {
+ findCommand->setShowRecordId(true);
+ addShowRecordIdMetaProj(findCommand);
+ }
+ } else if (name == "maxTimeMS") {
+ StatusWith<int> maxTimeMS = parseMaxTimeMS(e);
+ if (!maxTimeMS.isOK()) {
+ return maxTimeMS.getStatus();
+ }
+ findCommand->setMaxTimeMS(maxTimeMS.getValue());
+ }
+ }
}
- uassertStatusOK(qr->validate());
- return qr;
-}
-std::unique_ptr<QueryRequest> QueryRequest::makeFromFindCommandForTests(
- const BSONObj& cmdObj, bool isExplain, boost::optional<NamespaceString> nss, bool apiStrict) {
- return makeFromFindCommand(cmdObj, isExplain, nss, apiStrict);
+ return Status::OK();
}
-BSONObj QueryRequest::asFindCommand() const {
- BSONObjBuilder bob;
- asFindCommand(&bob);
- return bob.obj();
-}
+Status initFindCommand(int ntoskip,
+ int ntoreturn,
+ int queryOptions,
+ const BSONObj& queryObj,
+ const BSONObj& proj,
+ bool fromQueryMessage,
+ FindCommand* findCommand,
+ bool* explain) {
+ if (!proj.isEmpty()) {
+ findCommand->setProjection(proj.getOwned());
+ }
+ if (ntoskip) {
+ findCommand->setSkip(ntoskip);
+ }
-void QueryRequest::asFindCommand(BSONObjBuilder* cmdBuilder) const {
- _findCommand.serialize(BSONObj(), cmdBuilder);
-}
+ if (ntoreturn) {
+ if (ntoreturn < 0) {
+ if (ntoreturn == std::numeric_limits<int>::min()) {
+ // ntoreturn is negative but can't be negated.
+ return Status(ErrorCodes::BadValue, "bad ntoreturn value in query");
+ }
+ findCommand->setNtoreturn(-ntoreturn);
+ findCommand->setSingleBatch(true);
+ } else {
+ findCommand->setNtoreturn(ntoreturn);
+ }
+ }
-void QueryRequest::addShowRecordIdMetaProj() {
- if (getProj()["$recordId"]) {
- // There's already some projection on $recordId. Don't overwrite it.
- return;
+ // An ntoreturn of 1 is special because it also means to return at most one batch.
+ if (findCommand->getNtoreturn().value_or(0) == 1) {
+ findCommand->setSingleBatch(true);
}
- BSONObjBuilder projBob;
- projBob.appendElements(getProj());
- BSONObj metaRecordId = BSON("$recordId" << BSON("$meta" << QueryRequest::metaRecordId));
- projBob.append(metaRecordId.firstElement());
- setProj(projBob.obj());
+ // Initialize flags passed as 'queryOptions' bit vector.
+ initFromInt(queryOptions, findCommand);
+
+ if (fromQueryMessage) {
+ BSONElement queryField = queryObj["query"];
+ if (!queryField.isABSONObj()) {
+ queryField = queryObj["$query"];
+ }
+ if (queryField.isABSONObj()) {
+ findCommand->setFilter(queryField.embeddedObject().getOwned());
+ Status status = initFullQuery(queryObj, findCommand, explain);
+ if (!status.isOK()) {
+ return status;
+ }
+ } else {
+ findCommand->setFilter(queryObj.getOwned());
+ }
+ // It's not possible to specify readConcern in a legacy query message, so initialize it to
+ // an empty readConcern object, ie. equivalent to `readConcern: {}`. This ensures that
+ // mongos passes this empty readConcern to shards.
+ findCommand->setReadConcern(BSONObj());
+ } else {
+ // This is the debugging code path.
+ findCommand->setFilter(queryObj.getOwned());
+ }
+
+ return validateFindCommand(*findCommand);
}
-Status QueryRequest::validate() const {
+} // namespace
+
+Status validateFindCommand(const FindCommand& findCommand) {
// Min and Max objects must have the same fields.
- if (!getMin().isEmpty() && !getMax().isEmpty()) {
- if (!getMin().isFieldNamePrefixOf(getMax()) || (getMin().nFields() != getMax().nFields())) {
+ if (!findCommand.getMin().isEmpty() && !findCommand.getMax().isEmpty()) {
+ if (!findCommand.getMin().isFieldNamePrefixOf(findCommand.getMax()) ||
+ (findCommand.getMin().nFields() != findCommand.getMax().nFields())) {
return Status(ErrorCodes::Error(51176), "min and max must have the same field names");
}
}
- if ((getLimit() || getBatchSize()) && getNToReturn()) {
+ if ((findCommand.getLimit() || findCommand.getBatchSize()) && findCommand.getNtoreturn()) {
return Status(ErrorCodes::BadValue,
"'limit' or 'batchSize' fields can not be set with 'ntoreturn' field.");
}
// TODO SERVER-53060: When legacy query request is seperated, these validations can be moved to
// IDL.
- if (getSkip() && *getSkip() < 0) {
+ if (findCommand.getSkip() && *findCommand.getSkip() < 0) {
return Status(ErrorCodes::BadValue,
- str::stream()
- << "Skip value must be non-negative, but received: " << *getSkip());
+ str::stream() << "Skip value must be non-negative, but received: "
+ << *findCommand.getSkip());
}
- if (getLimit() && *getLimit() < 0) {
+ if (findCommand.getLimit() && *findCommand.getLimit() < 0) {
return Status(ErrorCodes::BadValue,
- str::stream()
- << "Limit value must be non-negative, but received: " << *getLimit());
+ str::stream() << "Limit value must be non-negative, but received: "
+ << *findCommand.getLimit());
}
- if (getBatchSize() && *getBatchSize() < 0) {
+ if (findCommand.getBatchSize() && *findCommand.getBatchSize() < 0) {
return Status(ErrorCodes::BadValue,
str::stream() << "BatchSize value must be non-negative, but received: "
- << *getBatchSize());
+ << *findCommand.getBatchSize());
}
- if (getNToReturn() && *getNToReturn() < 0) {
+ if (findCommand.getNtoreturn() && *findCommand.getNtoreturn() < 0) {
return Status(ErrorCodes::BadValue,
str::stream() << "NToReturn value must be non-negative, but received: "
- << *getNToReturn());
+ << *findCommand.getNtoreturn());
}
- if (getMaxTimeMS() < 0) {
+ int maxTimeMS = findCommand.getMaxTimeMS() ? static_cast<int>(*findCommand.getMaxTimeMS()) : 0;
+ if (maxTimeMS < 0) {
return Status(ErrorCodes::BadValue,
- str::stream() << "MaxTimeMS value must be non-negative, but received: "
- << getMaxTimeMS());
+ str::stream()
+ << "MaxTimeMS value must be non-negative, but received: " << maxTimeMS);
}
- if (_tailableMode != TailableModeEnum::kNormal) {
+ if (query_request_helper::getTailableMode(findCommand) != TailableModeEnum::kNormal) {
// Tailable cursors cannot have any sort other than {$natural: 1}.
- const BSONObj expectedSort = BSON(kNaturalSortField << 1);
- if (!getSort().isEmpty() &&
- SimpleBSONObjComparator::kInstance.evaluate(getSort() != expectedSort)) {
+ const BSONObj expectedSort = BSON(query_request_helper::kNaturalSortField << 1);
+ if (!findCommand.getSort().isEmpty() &&
+ SimpleBSONObjComparator::kInstance.evaluate(findCommand.getSort() != expectedSort)) {
return Status(ErrorCodes::BadValue,
"cannot use tailable option with a sort other than {$natural: 1}");
}
// Cannot indicate that you want a 'singleBatch' if the cursor is tailable.
- if (isSingleBatch()) {
+ if (findCommand.getSingleBatch()) {
return Status(ErrorCodes::BadValue,
"cannot use tailable option with the 'singleBatch' option");
}
}
- if (getRequestResumeToken()) {
- if (SimpleBSONObjComparator::kInstance.evaluate(getHint() !=
- BSON(kNaturalSortField << 1))) {
+ if (findCommand.getRequestResumeToken()) {
+ if (SimpleBSONObjComparator::kInstance.evaluate(
+ findCommand.getHint() != BSON(query_request_helper::kNaturalSortField << 1))) {
return Status(ErrorCodes::BadValue,
"hint must be {$natural:1} if 'requestResumeToken' is enabled");
}
- if (!getSort().isEmpty() &&
- SimpleBSONObjComparator::kInstance.evaluate(getSort() !=
- BSON(kNaturalSortField << 1))) {
+ if (!findCommand.getSort().isEmpty() &&
+ SimpleBSONObjComparator::kInstance.evaluate(
+ findCommand.getSort() != BSON(query_request_helper::kNaturalSortField << 1))) {
return Status(ErrorCodes::BadValue,
"sort must be unset or {$natural:1} if 'requestResumeToken' is enabled");
}
- if (!getResumeAfter().isEmpty()) {
- if (getResumeAfter().nFields() != 1 ||
- (getResumeAfter()["$recordId"].type() != BSONType::NumberLong &&
- getResumeAfter()["$recordId"].type() != BSONType::jstOID &&
- getResumeAfter()["$recordId"].type() != BSONType::jstNULL)) {
+ if (!findCommand.getResumeAfter().isEmpty()) {
+ if (findCommand.getResumeAfter().nFields() != 1 ||
+ (findCommand.getResumeAfter()["$recordId"].type() != BSONType::NumberLong &&
+ findCommand.getResumeAfter()["$recordId"].type() != BSONType::jstOID &&
+ findCommand.getResumeAfter()["$recordId"].type() != BSONType::jstNULL)) {
return Status(
ErrorCodes::BadValue,
"Malformed resume token: the '_resumeAfter' object must contain"
" exactly one field named '$recordId', of type NumberLong, jstOID or jstNULL.");
}
}
- } else if (!getResumeAfter().isEmpty()) {
+ } else if (!findCommand.getResumeAfter().isEmpty()) {
return Status(ErrorCodes::BadValue,
"'requestResumeToken' must be true if 'resumeAfter' is"
" specified");
}
+
return Status::OK();
}
-// static
-bool QueryRequest::isTextScoreMeta(BSONElement elt) {
+void refreshNSS(const NamespaceString& nss, FindCommand* findCommand) {
+ if (findCommand->getNamespaceOrUUID().uuid()) {
+ auto& nssOrUUID = findCommand->getNamespaceOrUUID();
+ nssOrUUID.setNss(nss);
+ }
+ invariant(findCommand->getNamespaceOrUUID().nss());
+}
+
+std::unique_ptr<FindCommand> makeFromFindCommand(const BSONObj& cmdObj,
+ boost::optional<NamespaceString> nss,
+ bool apiStrict) {
+
+ auto findCommand = std::make_unique<FindCommand>(
+ FindCommand::parse(IDLParserErrorContext("FindCommand", apiStrict), cmdObj));
+
+ // If there is an explicit namespace specified overwite it.
+ if (nss) {
+ auto& nssOrUuid = findCommand->getNamespaceOrUUID();
+ nssOrUuid.setNss(*nss);
+ }
+
+ addMetaProjection(findCommand.get());
+
+ if (findCommand->getSkip() && *findCommand->getSkip() == 0) {
+ findCommand->setSkip(boost::none);
+ }
+ if (findCommand->getLimit() && *findCommand->getLimit() == 0) {
+ findCommand->setLimit(boost::none);
+ }
+ uassertStatusOK(validateFindCommand(*findCommand));
+
+ return findCommand;
+}
+
+std::unique_ptr<FindCommand> makeFromFindCommandForTests(const BSONObj& cmdObj,
+ boost::optional<NamespaceString> nss,
+ bool apiStrict) {
+ return makeFromFindCommand(cmdObj, nss, apiStrict);
+}
+
+bool isTextScoreMeta(BSONElement elt) {
// elt must be foo: {$meta: "textScore"}
if (mongo::Object != elt.type()) {
return false;
@@ -233,7 +401,7 @@ bool QueryRequest::isTextScoreMeta(BSONElement elt) {
if (mongo::String != metaElt.type()) {
return false;
}
- if (StringData{metaElt.valuestr()} != QueryRequest::metaTextScore) {
+ if (StringData{metaElt.valuestr()} != metaTextScore) {
return false;
}
// must have exactly 1 element
@@ -243,323 +411,134 @@ bool QueryRequest::isTextScoreMeta(BSONElement elt) {
return true;
}
+void setTailableMode(TailableModeEnum tailableMode, FindCommand* findCommand) {
+ if (tailableMode == TailableModeEnum::kTailableAndAwaitData) {
+ findCommand->setAwaitData(true);
+ findCommand->setTailable(true);
+ } else if (tailableMode == TailableModeEnum::kTailable) {
+ findCommand->setTailable(true);
+ }
+}
+
+TailableModeEnum getTailableMode(const FindCommand& findCommand) {
+ return uassertStatusOK(
+ tailableModeFromBools(findCommand.getTailable(), findCommand.getAwaitData()));
+}
+
//
// Old QueryRequest parsing code: SOON TO BE DEPRECATED.
//
-// static
-StatusWith<std::unique_ptr<QueryRequest>> QueryRequest::fromLegacyQueryMessage(
- const QueryMessage& qm) {
- auto qr = std::make_unique<QueryRequest>(NamespaceString(qm.ns));
-
- Status status = qr->init(qm.ntoskip, qm.ntoreturn, qm.queryOptions, qm.query, qm.fields, true);
+StatusWith<std::unique_ptr<FindCommand>> fromLegacyQueryMessage(const QueryMessage& qm,
+ bool* explain) {
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString(qm.ns));
+
+ Status status = initFindCommand(qm.ntoskip,
+ qm.ntoreturn,
+ qm.queryOptions,
+ qm.query,
+ qm.fields,
+ true,
+ findCommand.get(),
+ explain);
if (!status.isOK()) {
return status;
}
- return std::move(qr);
+ return std::move(findCommand);
}
-StatusWith<std::unique_ptr<QueryRequest>> QueryRequest::fromLegacyQuery(
- NamespaceStringOrUUID nsOrUuid,
- const BSONObj& queryObj,
- const BSONObj& proj,
- int ntoskip,
- int ntoreturn,
- int queryOptions) {
- // Legacy command should prefer to serialize with UUID.
- auto qr = std::make_unique<QueryRequest>(std::move(nsOrUuid), false);
-
- Status status = qr->init(ntoskip, ntoreturn, queryOptions, queryObj, proj, true);
+StatusWith<std::unique_ptr<FindCommand>> fromLegacyQuery(NamespaceStringOrUUID nssOrUuid,
+ const BSONObj& queryObj,
+ const BSONObj& proj,
+ int ntoskip,
+ int ntoreturn,
+ int queryOptions,
+ bool* explain) {
+ auto findCommand = std::make_unique<FindCommand>(std::move(nssOrUuid));
+
+ Status status = initFindCommand(
+ ntoskip, ntoreturn, queryOptions, queryObj, proj, true, findCommand.get(), explain);
if (!status.isOK()) {
return status;
}
- return std::move(qr);
-}
-
-Status QueryRequest::init(int ntoskip,
- int ntoreturn,
- int queryOptions,
- const BSONObj& queryObj,
- const BSONObj& proj,
- bool fromQueryMessage) {
- if (!proj.isEmpty()) {
- _findCommand.setProjection(proj.getOwned());
- }
- if (ntoskip) {
- _findCommand.setSkip(ntoskip);
- }
-
- if (ntoreturn) {
- if (ntoreturn < 0) {
- if (ntoreturn == std::numeric_limits<int>::min()) {
- // ntoreturn is negative but can't be negated.
- return Status(ErrorCodes::BadValue, "bad ntoreturn value in query");
- }
- _findCommand.setNtoreturn(-ntoreturn);
- setSingleBatchField(true);
- } else {
- _findCommand.setNtoreturn(ntoreturn);
- }
- }
-
- // An ntoreturn of 1 is special because it also means to return at most one batch.
- if (getNToReturn().value_or(0) == 1) {
- setSingleBatchField(true);
- }
-
- // Initialize flags passed as 'queryOptions' bit vector.
- initFromInt(queryOptions);
-
- if (fromQueryMessage) {
- BSONElement queryField = queryObj["query"];
- if (!queryField.isABSONObj()) {
- queryField = queryObj["$query"];
- }
- if (queryField.isABSONObj()) {
- _findCommand.setFilter(queryField.embeddedObject().getOwned());
- Status status = initFullQuery(queryObj);
- if (!status.isOK()) {
- return status;
- }
- } else {
- _findCommand.setFilter(queryObj.getOwned());
- }
- // It's not possible to specify readConcern in a legacy query message, so initialize it to
- // an empty readConcern object, ie. equivalent to `readConcern: {}`. This ensures that
- // mongos passes this empty readConcern to shards.
- setReadConcern(BSONObj());
- } else {
- // This is the debugging code path.
- _findCommand.setFilter(queryObj.getOwned());
- }
-
- _hasReadPref = queryObj.hasField("$readPreference");
-
- return validate();
+ return std::move(findCommand);
}
-Status QueryRequest::initFullQuery(const BSONObj& top) {
- BSONObjIterator i(top);
-
- while (i.more()) {
- BSONElement e = i.next();
- StringData name = e.fieldNameStringData();
-
- if (name == "$orderby" || name == "orderby") {
- if (Object == e.type()) {
- setSort(e.embeddedObject().getOwned());
- } else if (Array == e.type()) {
- setSort(e.embeddedObject());
-
- // TODO: Is this ever used? I don't think so.
- // Quote:
- // This is for languages whose "objects" are not well ordered (JSON is well
- // ordered).
- // [ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
- // note: this is slow, but that is ok as order will have very few pieces
- BSONObjBuilder b;
- char p[2] = "0";
-
- while (1) {
- BSONObj j = getSort().getObjectField(p);
- if (j.isEmpty()) {
- break;
- }
- BSONElement e = j.firstElement();
- if (e.eoo()) {
- return Status(ErrorCodes::BadValue, "bad order array");
- }
- if (!e.isNumber()) {
- return Status(ErrorCodes::BadValue, "bad order array [2]");
- }
- b.append(e);
- (*p)++;
- if (!(*p <= '9')) {
- return Status(ErrorCodes::BadValue, "too many ordering elements");
- }
- }
-
- setSort(b.obj());
- } else {
- return Status(ErrorCodes::BadValue, "sort must be object or array");
- }
- } else if (name.startsWith("$")) {
- name = name.substr(1); // chop first char
- if (name == "explain") {
- // Won't throw.
- _explain = e.trueValue();
- } else if (name == "min") {
- if (!e.isABSONObj()) {
- return Status(ErrorCodes::BadValue, "$min must be a BSONObj");
- }
- setMin(e.embeddedObject().getOwned());
- } else if (name == "max") {
- if (!e.isABSONObj()) {
- return Status(ErrorCodes::BadValue, "$max must be a BSONObj");
- }
- setMax(e.embeddedObject().getOwned());
- } else if (name == "hint") {
- if (e.isABSONObj()) {
- setHint(e.embeddedObject().getOwned());
- } else if (String == e.type()) {
- setHint(e.wrap());
- } else {
- return Status(ErrorCodes::BadValue,
- "$hint must be either a string or nested object");
- }
- } else if (name == "returnKey") {
- // Won't throw.
- if (e.trueValue()) {
- setReturnKey(true);
- }
- } else if (name == "showDiskLoc") {
- // Won't throw.
- if (e.trueValue()) {
- setShowRecordId(true);
- addShowRecordIdMetaProj();
- }
- } else if (name == "maxTimeMS") {
- StatusWith<int> maxTimeMS = parseMaxTimeMS(e);
- if (!maxTimeMS.isOK()) {
- return maxTimeMS.getStatus();
- }
- setMaxTimeMS(maxTimeMS.getValue());
- }
- }
- }
-
- return Status::OK();
-}
-
-int QueryRequest::getOptions() const {
- int options = 0;
- if (_tailableMode == TailableModeEnum::kTailable) {
- options |= QueryOption_CursorTailable;
- } else if (_tailableMode == TailableModeEnum::kTailableAndAwaitData) {
- options |= QueryOption_CursorTailable;
- options |= QueryOption_AwaitData;
- }
- if (_slaveOk) {
- options |= QueryOption_SecondaryOk;
- }
- if (isNoCursorTimeout()) {
- options |= QueryOption_NoCursorTimeout;
- }
- if (_exhaust) {
- options |= QueryOption_Exhaust;
- }
- if (isAllowPartialResults()) {
- options |= QueryOption_PartialResults;
- }
- return options;
-}
-
-void QueryRequest::initFromInt(int options) {
- bool tailable = (options & QueryOption_CursorTailable) != 0;
- bool awaitData = (options & QueryOption_AwaitData) != 0;
- if (awaitData) {
- _findCommand.setAwaitData(true);
- }
- if (tailable) {
- _findCommand.setTailable(true);
- }
- _tailableMode = uassertStatusOK(tailableModeFromBools(tailable, awaitData));
- _slaveOk = (options & QueryOption_SecondaryOk) != 0;
- _exhaust = (options & QueryOption_Exhaust) != 0;
-
- if ((options & QueryOption_NoCursorTimeout) != 0) {
- setNoCursorTimeout(true);
- }
- if ((options & QueryOption_PartialResults) != 0) {
- setAllowPartialResults(true);
- }
-}
-
-void QueryRequest::addMetaProjection() {
- if (showRecordId()) {
- addShowRecordIdMetaProj();
- }
-}
-
-boost::optional<int64_t> QueryRequest::getEffectiveBatchSize() const {
- return getBatchSize() ? getBatchSize() : getNToReturn();
-}
-
-StatusWith<BSONObj> QueryRequest::asAggregationCommand() const {
+StatusWith<BSONObj> asAggregationCommand(const FindCommand& findCommand) {
BSONObjBuilder aggregationBuilder;
// First, check if this query has options that are not supported in aggregation.
- if (!getMin().isEmpty()) {
+ if (!findCommand.getMin().isEmpty()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kMinFieldName
<< " not supported in aggregation."};
}
- if (!getMax().isEmpty()) {
+ if (!findCommand.getMax().isEmpty()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kMaxFieldName
<< " not supported in aggregation."};
}
- if (returnKey()) {
+ if (findCommand.getReturnKey()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kReturnKeyFieldName
<< " not supported in aggregation."};
}
- if (showRecordId()) {
+ if (findCommand.getShowRecordId()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kShowRecordIdFieldName
<< " not supported in aggregation."};
}
- if (isTailable()) {
+ if (findCommand.getTailable()) {
return {ErrorCodes::InvalidPipelineOperator,
"Tailable cursors are not supported in aggregation."};
}
- if (isNoCursorTimeout()) {
+ if (findCommand.getNoCursorTimeout()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kNoCursorTimeoutFieldName
<< " not supported in aggregation."};
}
- if (isAllowPartialResults()) {
+ if (findCommand.getAllowPartialResults()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kAllowPartialResultsFieldName
<< " not supported in aggregation."};
}
- if (getNToReturn()) {
+ if (findCommand.getNtoreturn()) {
return {ErrorCodes::BadValue,
str::stream() << "Cannot convert to an aggregation if ntoreturn is set."};
}
- if (getSort()[kNaturalSortField]) {
+ if (findCommand.getSort()[query_request_helper::kNaturalSortField]) {
return {ErrorCodes::InvalidPipelineOperator,
- str::stream() << "Sort option " << kNaturalSortField
+ str::stream() << "Sort option " << query_request_helper::kNaturalSortField
<< " not supported in aggregation."};
}
// The aggregation command normally does not support the 'singleBatch' option, but we make a
// special exception if 'limit' is set to 1.
- if (isSingleBatch() && getLimit().value_or(0) != 1LL) {
+ if (findCommand.getSingleBatch() && findCommand.getLimit().value_or(0) != 1LL) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kSingleBatchFieldName
<< " not supported in aggregation."};
}
- if (isReadOnce()) {
+ if (findCommand.getReadOnce()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kReadOnceFieldName
<< " not supported in aggregation."};
}
- if (allowSpeculativeMajorityRead()) {
+ if (findCommand.getAllowSpeculativeMajorityRead()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kAllowSpeculativeMajorityReadFieldName
<< " not supported in aggregation."};
}
- if (getRequestResumeToken()) {
+ if (findCommand.getRequestResumeToken()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kRequestResumeTokenFieldName
<< " not supported in aggregation."};
}
- if (!getResumeAfter().isEmpty()) {
+ if (!findCommand.getResumeAfter().isEmpty()) {
return {ErrorCodes::InvalidPipelineOperator,
str::stream() << "Option " << FindCommand::kResumeAfterFieldName
<< " not supported in aggregation."};
@@ -567,72 +546,77 @@ StatusWith<BSONObj> QueryRequest::asAggregationCommand() const {
// Now that we've successfully validated this QR, begin building the aggregation command.
aggregationBuilder.append("aggregate",
- _findCommand.getNamespaceOrUUID().nss()
- ? _findCommand.getNamespaceOrUUID().nss()->coll()
+ findCommand.getNamespaceOrUUID().nss()
+ ? findCommand.getNamespaceOrUUID().nss()->coll()
: "");
// Construct an aggregation pipeline that finds the equivalent documents to this query request.
BSONArrayBuilder pipelineBuilder(aggregationBuilder.subarrayStart("pipeline"));
- if (!getFilter().isEmpty()) {
+ if (!findCommand.getFilter().isEmpty()) {
BSONObjBuilder matchBuilder(pipelineBuilder.subobjStart());
- matchBuilder.append("$match", getFilter());
+ matchBuilder.append("$match", findCommand.getFilter());
matchBuilder.doneFast();
}
- if (!getSort().isEmpty()) {
+ if (!findCommand.getSort().isEmpty()) {
BSONObjBuilder sortBuilder(pipelineBuilder.subobjStart());
- sortBuilder.append("$sort", getSort());
+ sortBuilder.append("$sort", findCommand.getSort());
sortBuilder.doneFast();
}
- if (getSkip()) {
+ if (findCommand.getSkip()) {
BSONObjBuilder skipBuilder(pipelineBuilder.subobjStart());
- skipBuilder.append("$skip", *getSkip());
+ skipBuilder.append("$skip", *findCommand.getSkip());
skipBuilder.doneFast();
}
- if (getLimit()) {
+ if (findCommand.getLimit()) {
BSONObjBuilder limitBuilder(pipelineBuilder.subobjStart());
- limitBuilder.append("$limit", *getLimit());
+ limitBuilder.append("$limit", *findCommand.getLimit());
limitBuilder.doneFast();
}
- if (!getProj().isEmpty()) {
+ if (!findCommand.getProjection().isEmpty()) {
BSONObjBuilder projectBuilder(pipelineBuilder.subobjStart());
- projectBuilder.append("$project", getProj());
+ projectBuilder.append("$project", findCommand.getProjection());
projectBuilder.doneFast();
}
pipelineBuilder.doneFast();
// The aggregation 'cursor' option is always set, regardless of the presence of batchSize.
BSONObjBuilder batchSizeBuilder(aggregationBuilder.subobjStart("cursor"));
- if (getBatchSize()) {
- batchSizeBuilder.append(FindCommand::kBatchSizeFieldName, *getBatchSize());
+ if (findCommand.getBatchSize()) {
+ batchSizeBuilder.append(FindCommand::kBatchSizeFieldName, *findCommand.getBatchSize());
}
batchSizeBuilder.doneFast();
// Other options.
- aggregationBuilder.append("collation", getCollation());
- if (getMaxTimeMS() > 0) {
- aggregationBuilder.append(cmdOptionMaxTimeMS, getMaxTimeMS());
+ aggregationBuilder.append("collation", findCommand.getCollation());
+ int maxTimeMS = findCommand.getMaxTimeMS() ? static_cast<int>(*findCommand.getMaxTimeMS()) : 0;
+ if (maxTimeMS > 0) {
+ aggregationBuilder.append(cmdOptionMaxTimeMS, maxTimeMS);
}
- if (!getHint().isEmpty()) {
- aggregationBuilder.append(FindCommand::kHintFieldName, getHint());
+ if (!findCommand.getHint().isEmpty()) {
+ aggregationBuilder.append(FindCommand::kHintFieldName, findCommand.getHint());
}
- if (getReadConcern()) {
- aggregationBuilder.append("readConcern", *getReadConcern());
+ if (findCommand.getReadConcern()) {
+ aggregationBuilder.append("readConcern", *findCommand.getReadConcern());
}
- if (!getUnwrappedReadPref().isEmpty()) {
- aggregationBuilder.append(FindCommand::kUnwrappedReadPrefFieldName, getUnwrappedReadPref());
+ if (!findCommand.getUnwrappedReadPref().isEmpty()) {
+ aggregationBuilder.append(FindCommand::kUnwrappedReadPrefFieldName,
+ findCommand.getUnwrappedReadPref());
}
- if (allowDiskUse()) {
- aggregationBuilder.append(FindCommand::kAllowDiskUseFieldName, allowDiskUse());
+ if (findCommand.getAllowDiskUse()) {
+ aggregationBuilder.append(FindCommand::kAllowDiskUseFieldName,
+ static_cast<bool>(findCommand.getAllowDiskUse()));
}
- if (getLegacyRuntimeConstants()) {
+ if (findCommand.getLegacyRuntimeConstants()) {
BSONObjBuilder rtcBuilder(
aggregationBuilder.subobjStart(FindCommand::kLegacyRuntimeConstantsFieldName));
- getLegacyRuntimeConstants()->serialize(&rtcBuilder);
+ findCommand.getLegacyRuntimeConstants()->serialize(&rtcBuilder);
rtcBuilder.doneFast();
}
- if (getLetParameters()) {
- aggregationBuilder.append(FindCommand::kLetFieldName, *getLetParameters());
+ if (findCommand.getLet()) {
+ aggregationBuilder.append(FindCommand::kLetFieldName, *findCommand.getLet());
}
return StatusWith<BSONObj>(aggregationBuilder.obj());
}
+
+} // namespace query_request_helper
} // namespace mongo
diff --git a/src/mongo/db/query/query_request_helper.h b/src/mongo/db/query/query_request_helper.h
new file mode 100644
index 00000000000..00497369379
--- /dev/null
+++ b/src/mongo/db/query/query_request_helper.h
@@ -0,0 +1,166 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+#include <string>
+
+#include "mongo/db/catalog/collection_options.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/operation_context.h"
+#include "mongo/db/query/find_command_gen.h"
+#include "mongo/db/query/tailable_mode.h"
+
+namespace mongo {
+
+class QueryMessage;
+class Status;
+template <typename T>
+class StatusWith;
+
+/**
+ * Parses the QueryMessage or find command received from the user and makes the various fields
+ * more easily accessible.
+ */
+namespace query_request_helper {
+
+static constexpr auto kMaxTimeMSOpOnlyField = "maxTimeMSOpOnly";
+
+// Field names for sorting options.
+static constexpr auto kNaturalSortField = "$natural";
+
+static constexpr auto kShardVersionField = "shardVersion";
+
+/**
+ * Returns a non-OK status if any property of the QR has a bad value (e.g. a negative skip
+ * value) or if there is a bad combination of options (e.g. awaitData is illegal without
+ * tailable).
+ */
+Status validateFindCommand(const FindCommand& findCommand);
+
+/**
+ * Parses a find command object, 'cmdObj'. Caller must indicate whether or not this lite
+ * parsed query is an explained query or not via 'isExplain'. Accepts a NSS with which
+ * to initialize the FindCommand if there is no UUID in cmdObj.
+ *
+ * Returns a heap allocated FindCommand on success or an error if 'cmdObj' is not well
+ * formed.
+ */
+std::unique_ptr<FindCommand> makeFromFindCommand(const BSONObj& cmdObj,
+ boost::optional<NamespaceString> nss,
+ bool apiStrict);
+
+std::unique_ptr<FindCommand> makeFromFindCommandForTests(
+ const BSONObj& cmdObj,
+ boost::optional<NamespaceString> nss = boost::none,
+ bool apiStrict = false);
+
+/**
+ * If _uuid exists for this FindCommand, update the value of _nss.
+ */
+void refreshNSS(const NamespaceString& nss, FindCommand* findCommand);
+
+/**
+ * Converts this FindCommand into an aggregation using $match. If this FindCommand has options
+ * that cannot be satisfied by aggregation, a non-OK status is returned and 'cmdBuilder' is not
+ * modified.
+ */
+StatusWith<BSONObj> asAggregationCommand(const FindCommand& findCommand);
+
+/**
+ * Helper function to identify text search sort key
+ * Example: {a: {$meta: "textScore"}}
+ */
+bool isTextScoreMeta(BSONElement elt);
+
+// Read preference is attached to commands in "wrapped" form, e.g.
+// { $query: { <cmd>: ... } , <kWrappedReadPrefField>: { ... } }
+//
+// However, mongos internally "unwraps" the read preference and adds it as a parameter to the
+// command, e.g.
+// { <cmd>: ... , <kUnwrappedReadPrefField>: { <kWrappedReadPrefField>: { ... } } }
+static constexpr auto kWrappedReadPrefField = "$readPreference";
+static constexpr auto kUnwrappedReadPrefField = "$queryOptions";
+
+// Names of the maxTimeMS command and query option.
+// Char arrays because they are used in static initialization.
+static constexpr auto cmdOptionMaxTimeMS = "maxTimeMS";
+static constexpr auto queryOptionMaxTimeMS = "$maxTimeMS";
+
+// Names of the $meta projection values.
+static constexpr auto metaGeoNearDistance = "geoNearDistance";
+static constexpr auto metaGeoNearPoint = "geoNearPoint";
+static constexpr auto metaRecordId = "recordId";
+static constexpr auto metaSortKey = "sortKey";
+static constexpr auto metaTextScore = "textScore";
+
+// A constant by which 'maxTimeMSOpOnly' values are allowed to exceed the max allowed value for
+// 'maxTimeMS'. This is because mongod and mongos server processes add a small amount to the
+// 'maxTimeMS' value they are given before passing it on as 'maxTimeMSOpOnly', to allow for
+// clock precision.
+static constexpr auto kMaxTimeMSOpOnlyMaxPadding = 100LL;
+
+static constexpr auto kDefaultBatchSize = 101ll;
+
+void setTailableMode(TailableModeEnum tailableMode, FindCommand* findCommand);
+
+TailableModeEnum getTailableMode(const FindCommand& findCommand);
+
+//
+// Old parsing code: SOON TO BE DEPRECATED.
+//
+
+/**
+ * Parse the provided QueryMessage and return a heap constructed FindCommand, which
+ * represents it or an error.
+ */
+StatusWith<std::unique_ptr<FindCommand>> fromLegacyQueryMessage(const QueryMessage& qm,
+ bool* explain);
+
+/**
+ * Parse the provided legacy query object and parameters to construct a FindCommand.
+ */
+StatusWith<std::unique_ptr<FindCommand>> fromLegacyQuery(NamespaceStringOrUUID nsOrUuid,
+ const BSONObj& queryObj,
+ const BSONObj& proj,
+ int ntoskip,
+ int ntoreturn,
+ int queryOptions,
+ bool* explain);
+
+StatusWith<std::unique_ptr<FindCommand>> fromLegacyQueryFindCommand(NamespaceStringOrUUID nsOrUuid,
+ const BSONObj& queryObj,
+ const BSONObj& proj,
+ int ntoskip,
+ int ntoreturn,
+ int queryOptions);
+
+} // namespace query_request_helper
+} // namespace mongo
diff --git a/src/mongo/db/query/query_request_test.cpp b/src/mongo/db/query/query_request_test.cpp
index adee5c43cfc..adb40fa212f 100644
--- a/src/mongo/db/query/query_request_test.cpp
+++ b/src/mongo/db/query/query_request_test.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/json.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/pipeline/aggregation_request_helper.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/service_context_test_fixture.h"
#include "mongo/unittest/unittest.h"
@@ -53,142 +53,142 @@ using unittest::assertGet;
static const NamespaceString testns("testdb.testcoll");
TEST(QueryRequestTest, LimitWithNToReturn) {
- QueryRequest qr(testns);
- qr.setLimit(1);
- qr.setNToReturn(0);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setLimit(1);
+ findCommand.setNtoreturn(0);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, BatchSizeWithNToReturn) {
- QueryRequest qr(testns);
- qr.setBatchSize(0);
- qr.setNToReturn(0);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setBatchSize(0);
+ findCommand.setNtoreturn(0);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, NegativeSkip) {
- QueryRequest qr(testns);
- qr.setSkip(-1);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setSkip(-1);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ZeroSkip) {
- QueryRequest qr(testns);
- qr.setSkip(0);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setSkip(0);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, PositiveSkip) {
- QueryRequest qr(testns);
- qr.setSkip(1);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setSkip(1);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, NegativeLimit) {
- QueryRequest qr(testns);
- qr.setLimit(-1);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setLimit(-1);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ZeroLimit) {
- QueryRequest qr(testns);
- qr.setLimit(0);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setLimit(0);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, PositiveLimit) {
- QueryRequest qr(testns);
- qr.setLimit(1);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setLimit(1);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, NegativeBatchSize) {
- QueryRequest qr(testns);
- qr.setBatchSize(-1);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setBatchSize(-1);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ZeroBatchSize) {
- QueryRequest qr(testns);
- qr.setBatchSize(0);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setBatchSize(0);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, PositiveBatchSize) {
- QueryRequest qr(testns);
- qr.setBatchSize(1);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setBatchSize(1);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, NegativeNToReturn) {
- QueryRequest qr(testns);
- qr.setNToReturn(-1);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setNtoreturn(-1);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ZeroNToReturn) {
- QueryRequest qr(testns);
- qr.setNToReturn(0);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setNtoreturn(0);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, PositiveNToReturn) {
- QueryRequest qr(testns);
- qr.setNToReturn(1);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setNtoreturn(1);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, NegativeMaxTimeMS) {
- QueryRequest qr(testns);
- qr.setMaxTimeMS(-1);
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMaxTimeMS(-1);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ZeroMaxTimeMS) {
- QueryRequest qr(testns);
- qr.setMaxTimeMS(0);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMaxTimeMS(0);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, PositiveMaxTimeMS) {
- QueryRequest qr(testns);
- qr.setMaxTimeMS(1);
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMaxTimeMS(1);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ValidSortOrder) {
- QueryRequest qr(testns);
- qr.setSort(fromjson("{a: 1}"));
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setSort(fromjson("{a: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, DoesNotErrorOnInvalidSortPattern) {
- QueryRequest qr(testns);
- qr.setSort(fromjson("{a: \"\"}"));
- // QueryRequest isn't responsible for validating the sort pattern, so it is considered valid
+ FindCommand findCommand(testns);
+ findCommand.setSort(fromjson("{a: \"\"}"));
+ // FindCommand isn't responsible for validating the sort pattern, so it is considered valid
// even though the sort pattern {a: ""} is not well-formed.
- ASSERT_OK(qr.validate());
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, MinFieldsNotPrefixOfMax) {
- QueryRequest qr(testns);
- qr.setMin(fromjson("{a: 1}"));
- qr.setMax(fromjson("{b: 1}"));
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMin(fromjson("{a: 1}"));
+ findCommand.setMax(fromjson("{b: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, MinFieldsMoreThanMax) {
- QueryRequest qr(testns);
- qr.setMin(fromjson("{a: 1, b: 1}"));
- qr.setMax(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMin(fromjson("{a: 1, b: 1}"));
+ findCommand.setMax(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, MinFieldsLessThanMax) {
- QueryRequest qr(testns);
- qr.setMin(fromjson("{a: 1}"));
- qr.setMax(fromjson("{a: 1, b: 1}"));
- ASSERT_NOT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setMin(fromjson("{a: 1}"));
+ findCommand.setMax(fromjson("{a: 1, b: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ForbidTailableWithNonNaturalSort) {
@@ -197,8 +197,7 @@ TEST(QueryRequestTest, ForbidTailableWithNonNaturalSort) {
"tailable: true,"
"sort: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
@@ -209,8 +208,7 @@ TEST(QueryRequestTest, ForbidTailableWithSingleBatch) {
"tailable: true,"
"singleBatch: true, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
@@ -221,10 +219,9 @@ TEST(QueryRequestTest, AllowTailableWithNaturalSort) {
"tailable: true,"
"sort: {$natural: 1}, '$db': 'test'}");
- bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
- ASSERT_TRUE(qr->isTailable());
- ASSERT_BSONOBJ_EQ(qr->getSort(), BSON("$natural" << 1));
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(cmdObj);
+ ASSERT_TRUE(findCommand->getTailable());
+ ASSERT_BSONOBJ_EQ(findCommand->getSort(), BSON("$natural" << 1));
}
//
@@ -232,122 +229,122 @@ TEST(QueryRequestTest, AllowTailableWithNaturalSort) {
//
TEST(QueryRequestTest, ValidSortProj) {
- QueryRequest qr(testns);
- qr.setProj(fromjson("{a: 1}"));
- qr.setSort(fromjson("{a: 1}"));
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setProjection(fromjson("{a: 1}"));
+ findCommand.setSort(fromjson("{a: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
- QueryRequest metaQR(testns);
- metaQR.setProj(fromjson("{a: {$meta: \"textScore\"}}"));
- metaQR.setSort(fromjson("{a: {$meta: \"textScore\"}}"));
- ASSERT_OK(metaQR.validate());
+ FindCommand metaFC(testns);
+ metaFC.setProjection(fromjson("{a: {$meta: \"textScore\"}}"));
+ metaFC.setSort(fromjson("{a: {$meta: \"textScore\"}}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(metaFC));
}
TEST(QueryRequestTest, TextScoreMetaSortOnFieldDoesNotRequireMetaProjection) {
- QueryRequest qr(testns);
- qr.setProj(fromjson("{b: 1}"));
- qr.setSort(fromjson("{a: {$meta: 'textScore'}}"));
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setProjection(fromjson("{b: 1}"));
+ findCommand.setSort(fromjson("{a: {$meta: 'textScore'}}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, TextScoreMetaProjectionDoesNotRequireTextScoreMetaSort) {
- QueryRequest qr(testns);
- qr.setProj(fromjson("{a: {$meta: \"textScore\"}}"));
- qr.setSort(fromjson("{b: 1}"));
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setProjection(fromjson("{a: {$meta: \"textScore\"}}"));
+ findCommand.setSort(fromjson("{b: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, RequestResumeTokenWithHint) {
- QueryRequest qr(testns);
- qr.setRequestResumeToken(true);
- ASSERT_NOT_OK(qr.validate());
- qr.setHint(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.validate());
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
+ FindCommand findCommand(testns);
+ findCommand.setRequestResumeToken(true);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setHint(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, RequestResumeTokenWithSort) {
- QueryRequest qr(testns);
- qr.setRequestResumeToken(true);
+ FindCommand findCommand(testns);
+ findCommand.setRequestResumeToken(true);
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
- qr.setSort(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.validate());
- qr.setSort(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setSort(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setSort(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, InvalidResumeAfterWrongRecordIdType) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1);
- qr.setResumeAfter(resumeAfter);
- qr.setRequestResumeToken(true);
+ findCommand.setResumeAfter(resumeAfter);
+ findCommand.setRequestResumeToken(true);
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_NOT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
resumeAfter = BSON("$recordId" << 1LL);
- qr.setResumeAfter(resumeAfter);
- ASSERT_OK(qr.validate());
+ findCommand.setResumeAfter(resumeAfter);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, InvalidResumeAfterExtraField) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1LL << "$extra" << 1);
- qr.setResumeAfter(resumeAfter);
- qr.setRequestResumeToken(true);
+ findCommand.setResumeAfter(resumeAfter);
+ findCommand.setRequestResumeToken(true);
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_NOT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ResumeAfterWithHint) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1LL);
- qr.setResumeAfter(resumeAfter);
- qr.setRequestResumeToken(true);
- ASSERT_NOT_OK(qr.validate());
- qr.setHint(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.validate());
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
+ findCommand.setResumeAfter(resumeAfter);
+ findCommand.setRequestResumeToken(true);
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setHint(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ResumeAfterWithSort) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1LL);
- qr.setResumeAfter(resumeAfter);
- qr.setRequestResumeToken(true);
+ findCommand.setResumeAfter(resumeAfter);
+ findCommand.setRequestResumeToken(true);
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
- qr.setSort(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.validate());
- qr.setSort(fromjson("{$natural: 1}"));
- ASSERT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setSort(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setSort(fromjson("{$natural: 1}"));
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ResumeNoSpecifiedRequestResumeToken) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1LL);
- qr.setResumeAfter(resumeAfter);
+ findCommand.setResumeAfter(resumeAfter);
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- ASSERT_NOT_OK(qr.validate());
- qr.setRequestResumeToken(true);
- ASSERT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ ASSERT_NOT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setRequestResumeToken(true);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
TEST(QueryRequestTest, ExplicitEmptyResumeAfter) {
- QueryRequest qr(NamespaceString::kRsOplogNamespace);
+ FindCommand findCommand(NamespaceString::kRsOplogNamespace);
BSONObj resumeAfter = fromjson("{}");
// Hint must be explicitly set for the query request to validate.
- qr.setHint(fromjson("{$natural: 1}"));
- qr.setResumeAfter(resumeAfter);
- ASSERT_OK(qr.validate());
- qr.setRequestResumeToken(true);
- ASSERT_OK(qr.validate());
+ findCommand.setHint(fromjson("{$natural: 1}"));
+ findCommand.setResumeAfter(resumeAfter);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
+ findCommand.setRequestResumeToken(true);
+ ASSERT_OK(query_request_helper::validateFindCommand(findCommand));
}
//
@@ -357,7 +354,7 @@ TEST(QueryRequestTest, ExplicitEmptyResumeAfter) {
bool isFirstElementTextScoreMeta(const char* sortStr) {
BSONObj sortObj = fromjson(sortStr);
BSONElement elt = sortObj.firstElement();
- bool result = QueryRequest::isTextScoreMeta(elt);
+ bool result = query_request_helper::isTextScoreMeta(elt);
return result;
}
@@ -384,8 +381,7 @@ TEST(QueryRequestTest, ParseFromCommandBasic) {
"sort: {a: 1},"
"projection: {_id: 0, a: 1}, '$db': 'test'}");
- bool isExplain = false;
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, ParseFromCommandWithOptions) {
@@ -396,11 +392,10 @@ TEST(QueryRequestTest, ParseFromCommandWithOptions) {
"projection: {_id: 0, a: 1},"
"showRecordId: true, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
// Make sure the values from the command BSON are reflected in the QR.
- ASSERT(qr->showRecordId());
+ ASSERT(findCommand->getShowRecordId());
}
TEST(QueryRequestTest, ParseFromCommandHintAsString) {
@@ -409,10 +404,9 @@ TEST(QueryRequestTest, ParseFromCommandHintAsString) {
"filter: {a: 1},"
"hint: 'foo_1', '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- BSONObj hintObj = qr->getHint();
+ BSONObj hintObj = findCommand->getHint();
ASSERT_BSONOBJ_EQ(BSON("$hint"
<< "foo_1"),
hintObj);
@@ -424,8 +418,7 @@ TEST(QueryRequestTest, ParseFromCommandValidSortProj) {
"projection: {a: 1},"
"sort: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, ParseFromCommandValidSortProjMeta) {
@@ -434,8 +427,7 @@ TEST(QueryRequestTest, ParseFromCommandValidSortProjMeta) {
"projection: {a: {$meta: 'textScore'}},"
"sort: {a: {$meta: 'textScore'}}, '$db': 'test'}");
- bool isExplain = false;
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, ParseFromCommandAllFlagsTrue) {
@@ -448,17 +440,15 @@ TEST(QueryRequestTest, ParseFromCommandAllFlagsTrue) {
"readOnce: true,"
"allowSpeculativeMajorityRead: true, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
// Test that all the flags got set to true.
- ASSERT(qr->isTailable());
- ASSERT(!qr->isSlaveOk());
- ASSERT(qr->isNoCursorTimeout());
- ASSERT(qr->isTailableAndAwaitData());
- ASSERT(qr->isAllowPartialResults());
- ASSERT(qr->isReadOnce());
- ASSERT(qr->allowSpeculativeMajorityRead());
+ ASSERT(findCommand->getTailable());
+ ASSERT(findCommand->getNoCursorTimeout());
+ ASSERT(findCommand->getTailable() && findCommand->getAwaitData());
+ ASSERT(findCommand->getAllowPartialResults());
+ ASSERT(findCommand->getReadOnce());
+ ASSERT(findCommand->getAllowSpeculativeMajorityRead());
}
TEST(QueryRequestTest, OplogReplayFlagIsAllowedButIgnored) {
@@ -466,12 +456,11 @@ TEST(QueryRequestTest, OplogReplayFlagIsAllowedButIgnored) {
<< "testns"
<< "oplogReplay" << true << "tailable" << true << "$db"
<< "test");
- const bool isExplain = false;
const NamespaceString nss{"test.testns"};
- auto qr = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(cmdObj);
// Verify that the 'oplogReplay' flag does not appear if we reserialize the request.
- auto reserialized = qr->asFindCommand();
+ auto reserialized = findCommand->toBSON(BSONObj());
ASSERT_BSONOBJ_EQ(reserialized,
BSON("find"
<< "testns"
@@ -481,9 +470,8 @@ TEST(QueryRequestTest, OplogReplayFlagIsAllowedButIgnored) {
TEST(QueryRequestTest, ParseFromCommandReadOnceDefaultsToFalse) {
BSONObj cmdObj = fromjson("{find: 'testns', '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT(!qr->isReadOnce());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT(!findCommand->getReadOnce());
}
TEST(QueryRequestTest, ParseFromCommandValidMinMax) {
@@ -493,12 +481,11 @@ TEST(QueryRequestTest, ParseFromCommandValidMinMax) {
"min: {a: 1},"
"max: {a: 2}, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
BSONObj expectedMin = BSON("a" << 1);
- ASSERT_EQUALS(0, expectedMin.woCompare(qr->getMin()));
+ ASSERT_EQUALS(0, expectedMin.woCompare(findCommand->getMin()));
BSONObj expectedMax = BSON("a" << 2);
- ASSERT_EQUALS(0, expectedMax.woCompare(qr->getMax()));
+ ASSERT_EQUALS(0, expectedMax.woCompare(findCommand->getMax()));
}
TEST(QueryRequestTest, ParseFromCommandAllNonOptionFields) {
@@ -519,32 +506,31 @@ TEST(QueryRequestTest, ParseFromCommandAllNonOptionFields) {
"singleBatch: false, '$db': 'test'}")
.addField(rtcObj["runtimeConstants"]);
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
// Check the values inside the QR.
BSONObj expectedQuery = BSON("a" << 1);
- ASSERT_EQUALS(0, expectedQuery.woCompare(qr->getFilter()));
+ ASSERT_EQUALS(0, expectedQuery.woCompare(findCommand->getFilter()));
BSONObj expectedSort = BSON("b" << 1);
- ASSERT_EQUALS(0, expectedSort.woCompare(qr->getSort()));
+ ASSERT_EQUALS(0, expectedSort.woCompare(findCommand->getSort()));
BSONObj expectedProj = BSON("c" << 1);
- ASSERT_EQUALS(0, expectedProj.woCompare(qr->getProj()));
+ ASSERT_EQUALS(0, expectedProj.woCompare(findCommand->getProjection()));
BSONObj expectedHint = BSON("d" << 1);
- ASSERT_EQUALS(0, expectedHint.woCompare(qr->getHint()));
+ ASSERT_EQUALS(0, expectedHint.woCompare(findCommand->getHint()));
BSONObj expectedReadConcern = BSON("e" << 1);
- ASSERT(qr->getReadConcern());
- ASSERT_BSONOBJ_EQ(expectedReadConcern, *qr->getReadConcern());
+ ASSERT(findCommand->getReadConcern());
+ ASSERT_BSONOBJ_EQ(expectedReadConcern, *findCommand->getReadConcern());
BSONObj expectedUnwrappedReadPref = BSON("$readPreference"
<< "secondary");
- ASSERT_EQUALS(0, expectedUnwrappedReadPref.woCompare(qr->getUnwrappedReadPref()));
+ ASSERT_EQUALS(0, expectedUnwrappedReadPref.woCompare(findCommand->getUnwrappedReadPref()));
BSONObj expectedCollation = BSON("f" << 1);
- ASSERT_EQUALS(0, expectedCollation.woCompare(qr->getCollation()));
- ASSERT_EQUALS(3, *qr->getLimit());
- ASSERT_EQUALS(5, *qr->getSkip());
- ASSERT_EQUALS(90, *qr->getBatchSize());
- ASSERT(qr->getLegacyRuntimeConstants().has_value());
- ASSERT_EQUALS(qr->getLegacyRuntimeConstants()->getLocalNow(), rtc.getLocalNow());
- ASSERT_EQUALS(qr->getLegacyRuntimeConstants()->getClusterTime(), rtc.getClusterTime());
- ASSERT(!qr->isSingleBatch());
+ ASSERT_EQUALS(0, expectedCollation.woCompare(findCommand->getCollation()));
+ ASSERT_EQUALS(3, *findCommand->getLimit());
+ ASSERT_EQUALS(5, *findCommand->getSkip());
+ ASSERT_EQUALS(90, *findCommand->getBatchSize());
+ ASSERT(findCommand->getLegacyRuntimeConstants().has_value());
+ ASSERT_EQUALS(findCommand->getLegacyRuntimeConstants()->getLocalNow(), rtc.getLocalNow());
+ ASSERT_EQUALS(findCommand->getLegacyRuntimeConstants()->getClusterTime(), rtc.getClusterTime());
+ ASSERT(!findCommand->getSingleBatch());
}
TEST(QueryRequestTest, ParseFromCommandLargeLimit) {
@@ -553,10 +539,9 @@ TEST(QueryRequestTest, ParseFromCommandLargeLimit) {
"filter: {a: 1},"
"limit: 8000000000, '$db': 'test'}"); // 8 * 1000 * 1000 * 1000
- const bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *qr->getLimit());
+ ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *findCommand->getLimit());
}
TEST(QueryRequestTest, ParseFromCommandLargeBatchSize) {
@@ -565,10 +550,9 @@ TEST(QueryRequestTest, ParseFromCommandLargeBatchSize) {
"filter: {a: 1},"
"batchSize: 8000000000, '$db': 'test'}"); // 8 * 1000 * 1000 * 1000
- const bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *qr->getBatchSize());
+ ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *findCommand->getBatchSize());
}
TEST(QueryRequestTest, ParseFromCommandLargeSkip) {
@@ -577,10 +561,9 @@ TEST(QueryRequestTest, ParseFromCommandLargeSkip) {
"filter: {a: 1},"
"skip: 8000000000, '$db': 'test'}"); // 8 * 1000 * 1000 * 1000
- const bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *qr->getSkip());
+ ASSERT_EQUALS(8LL * 1000 * 1000 * 1000, *findCommand->getSkip());
}
//
@@ -592,8 +575,7 @@ TEST(QueryRequestTest, ParseFromCommandQueryWrongType) {
"{find: 'testns',"
"filter: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -604,8 +586,7 @@ TEST(QueryRequestTest, ParseFromCommandSortWrongType) {
"filter: {a: 1},"
"sort: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -617,8 +598,7 @@ TEST(QueryRequestTest, ParseFromCommandProjWrongType) {
"filter: {a: 1},"
"projection: 'foo', '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -631,8 +611,7 @@ TEST(QueryRequestTest, ParseFromCommandSkipWrongType) {
"skip: '5',"
"projection: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -645,8 +624,7 @@ TEST(QueryRequestTest, ParseFromCommandLimitWrongType) {
"limit: '5',"
"projection: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -659,8 +637,7 @@ TEST(QueryRequestTest, ParseFromCommandSingleBatchWrongType) {
"singleBatch: 'false',"
"projection: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -672,8 +649,7 @@ TEST(QueryRequestTest, ParseFromCommandUnwrappedReadPrefWrongType) {
"filter: {a: 1},"
"$queryOptions: 1, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -685,8 +661,7 @@ TEST(QueryRequestTest, ParseFromCommandMaxTimeMSWrongType) {
"filter: {a: 1},"
"maxTimeMS: true, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
@@ -698,8 +673,7 @@ TEST(QueryRequestTest, ParseFromCommandMaxWrongType) {
"filter: {a: 1},"
"max: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -711,8 +685,7 @@ TEST(QueryRequestTest, ParseFromCommandMinWrongType) {
"filter: {a: 1},"
"min: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -723,8 +696,7 @@ TEST(QueryRequestTest, ParseFromCommandReturnKeyWrongType) {
"filter: {a: 1},"
"returnKey: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -735,8 +707,7 @@ TEST(QueryRequestTest, ParseFromCommandShowRecordIdWrongType) {
"filter: {a: 1},"
"showRecordId: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -747,8 +718,7 @@ TEST(QueryRequestTest, ParseFromCommandTailableWrongType) {
"filter: {a: 1},"
"tailable: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -759,9 +729,8 @@ TEST(QueryRequestTest, ParseFromCommandSlaveOkWrongType) {
"filter: {a: 1},"
"slaveOk: 3, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 40415);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 40415);
}
TEST(QueryRequestTest, ParseFromCommandOplogReplayWrongType) {
@@ -770,8 +739,7 @@ TEST(QueryRequestTest, ParseFromCommandOplogReplayWrongType) {
"filter: {a: 1},"
"oplogReplay: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -782,8 +750,7 @@ TEST(QueryRequestTest, ParseFromCommandNoCursorTimeoutWrongType) {
"filter: {a: 1},"
"noCursorTimeout: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -795,8 +762,7 @@ TEST(QueryRequestTest, ParseFromCommandAwaitDataWrongType) {
"tailable: true,"
"awaitData: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -808,9 +774,8 @@ TEST(QueryRequestTest, ParseFromCommandExhaustWrongType) {
"filter: {a: 1},"
"exhaust: 3, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 40415);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 40415);
}
@@ -820,8 +785,7 @@ TEST(QueryRequestTest, ParseFromCommandPartialWrongType) {
"filter: {a: 1},"
"allowPartialResults: 3, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -832,8 +796,7 @@ TEST(QueryRequestTest, ParseFromCommandReadConcernWrongType) {
"filter: {a: 1},"
"readConcern: 'foo', '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -844,8 +807,7 @@ TEST(QueryRequestTest, ParseFromCommandCollationWrongType) {
"filter: {a: 1},"
"collation: 'foo', '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -855,8 +817,7 @@ TEST(QueryRequestTest, ParseFromCommandReadOnceWrongType) {
"{find: 'testns',"
"readOnce: 1, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -869,8 +830,7 @@ TEST(QueryRequestTest, ParseFromCommandLegacyRuntimeConstantsWrongType) {
<< "$db"
<< "test");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::TypeMismatch);
}
@@ -885,8 +845,7 @@ TEST(QueryRequestTest, ParseFromCommandLegacyRuntimeConstantsSubfieldsWrongType)
<< "shouldBeTimestamp")
<< "$db"
<< "test");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
AssertionException,
ErrorCodes::TypeMismatch);
}
@@ -900,8 +859,7 @@ TEST(QueryRequestTest, ParseFromCommandNegativeSkipError) {
"{find: 'testns',"
"skip: -3,"
"filter: {a: 3}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
@@ -911,10 +869,9 @@ TEST(QueryRequestTest, ParseFromCommandSkipIsZero) {
"{find: 'testns',"
"skip: 0,"
"filter: {a: 3}, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT_BSONOBJ_EQ(BSON("a" << 3), qr->getFilter());
- ASSERT_FALSE(qr->getSkip());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT_BSONOBJ_EQ(BSON("a" << 3), findCommand->getFilter());
+ ASSERT_FALSE(findCommand->getSkip());
}
TEST(QueryRequestTest, ParseFromCommandNegativeLimitError) {
@@ -922,8 +879,7 @@ TEST(QueryRequestTest, ParseFromCommandNegativeLimitError) {
"{find: 'testns',"
"limit: -3,"
"filter: {a: 3}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
@@ -933,10 +889,9 @@ TEST(QueryRequestTest, ParseFromCommandLimitIsZero) {
"{find: 'testns',"
"limit: 0,"
"filter: {a: 3}, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT_BSONOBJ_EQ(BSON("a" << 3), qr->getFilter());
- ASSERT_FALSE(qr->getLimit());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT_BSONOBJ_EQ(BSON("a" << 3), findCommand->getFilter());
+ ASSERT_FALSE(findCommand->getLimit());
}
TEST(QueryRequestTest, ParseFromCommandNegativeBatchSizeError) {
@@ -944,29 +899,26 @@ TEST(QueryRequestTest, ParseFromCommandNegativeBatchSizeError) {
"{find: 'testns',"
"batchSize: -10,"
"filter: {a: 3}, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
TEST(QueryRequestTest, ParseFromCommandBatchSizeZero) {
BSONObj cmdObj = fromjson("{find: 'testns', batchSize: 0, '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT(qr->getBatchSize());
- ASSERT_EQ(0, *qr->getBatchSize());
- ASSERT(!qr->getLimit());
+ ASSERT(findCommand->getBatchSize());
+ ASSERT_EQ(0, *findCommand->getBatchSize());
+ ASSERT(!findCommand->getLimit());
}
TEST(QueryRequestTest, ParseFromCommandDefaultBatchSize) {
BSONObj cmdObj = fromjson("{find: 'testns', '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT(!qr->getBatchSize());
- ASSERT(!qr->getLimit());
+ ASSERT(!findCommand->getBatchSize());
+ ASSERT(!findCommand->getLimit());
}
TEST(QueryRequestTest, ParseFromCommandRequestResumeToken) {
@@ -976,9 +928,8 @@ TEST(QueryRequestTest, ParseFromCommandRequestResumeToken) {
<< "$_requestResumeToken" << true << "$db"
<< "test");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT(qr->getRequestResumeToken());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT(findCommand->getRequestResumeToken());
}
TEST(QueryRequestTest, ParseFromCommandResumeToken) {
@@ -989,10 +940,9 @@ TEST(QueryRequestTest, ParseFromCommandResumeToken) {
<< BSON("$recordId" << 1LL) << "$db"
<< "test");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT(!qr->getResumeAfter().isEmpty());
- ASSERT(qr->getRequestResumeToken());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT(!findCommand->getResumeAfter().isEmpty());
+ ASSERT(findCommand->getRequestResumeToken());
}
TEST(QueryRequestTest, ParseFromCommandEmptyResumeToken) {
@@ -1004,14 +954,13 @@ TEST(QueryRequestTest, ParseFromCommandEmptyResumeToken) {
<< "$_requestResumeToken" << true << "$_resumeAfter" << resumeAfter << "$db"
<< "test");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT(qr->getRequestResumeToken());
- ASSERT(qr->getResumeAfter().isEmpty());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT(findCommand->getRequestResumeToken());
+ ASSERT(findCommand->getResumeAfter().isEmpty());
}
//
-// Test asFindCommand ns and uuid variants.
+// Test FindCommand object ns and uuid variants.
//
TEST(QueryRequestTest, AsFindCommandAllNonOptionFields) {
@@ -1031,9 +980,8 @@ TEST(QueryRequestTest, AsFindCommandAllNonOptionFields) {
"readConcern: {e: 1}, '$db': 'test'}")
.addField(storage["runtimeConstants"]);
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), qr->asFindCommand());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), findCommand->toBSON(BSONObj()));
}
TEST(QueryRequestTest, AsFindCommandWithUuidAllNonOptionFields) {
@@ -1055,17 +1003,16 @@ TEST(QueryRequestTest, AsFindCommandWithUuidAllNonOptionFields) {
"readConcern: {e: 1}, '$db': 'test'}")
.addField(storage["runtimeConstants"]);
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), qr->asFindCommand());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), findCommand->toBSON(BSONObj()));
}
TEST(QueryRequestTest, AsFindCommandWithUuidNoAvailableNamespace) {
BSONObj cmdObj =
fromjson("{find: { \"$binary\" : \"ASNFZ4mrze/ty6mHZUMhAQ==\", \"$type\" : \"04\" }}");
- QueryRequest qr(NamespaceStringOrUUID(
+ FindCommand findCommand(NamespaceStringOrUUID(
"test", UUID::parse("01234567-89ab-cdef-edcb-a98765432101").getValue()));
- ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), qr.asFindCommand());
+ ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), findCommand.toBSON(BSONObj()));
}
TEST(QueryRequestTest, AsFindCommandWithResumeToken) {
@@ -1076,9 +1023,8 @@ TEST(QueryRequestTest, AsFindCommandWithResumeToken) {
<< BSON("$recordId" << 1LL) << "$db"
<< "test");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), qr->asFindCommand());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT_BSONOBJ_EQ(cmdObj.removeField("$db"), findCommand->toBSON(BSONObj()));
}
TEST(QueryRequestTest, AsFindCommandWithEmptyResumeToken) {
@@ -1089,14 +1035,13 @@ TEST(QueryRequestTest, AsFindCommandWithEmptyResumeToken) {
<< "hint" << BSON("$natural" << 1) << "sort" << BSON("$natural" << 1)
<< "$_requestResumeToken" << true << "$_resumeAfter" << resumeAfter << "$db"
<< "test");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
- ASSERT(qr->asFindCommand().getField("$_resumeAftr").eoo());
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
+ ASSERT(findCommand->toBSON(BSONObj()).getField("$_resumeAftr").eoo());
}
//
//
-// Errors checked in QueryRequest::validate().
+// Errors checked in query_request_helper::validateFindCommand().
//
TEST(QueryRequestTest, ParseFromCommandMinMaxDifferentFieldsError) {
@@ -1104,9 +1049,8 @@ TEST(QueryRequestTest, ParseFromCommandMinMaxDifferentFieldsError) {
"{find: 'testns',"
"min: {a: 3},"
"max: {b: 4}, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 51176);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 51176);
}
TEST(QueryRequestTest, ParseCommandAllowNonMetaSortOnFieldWithMetaProject) {
@@ -1116,14 +1060,13 @@ TEST(QueryRequestTest, ParseCommandAllowNonMetaSortOnFieldWithMetaProject) {
"{find: 'testns',"
"projection: {a: {$meta: 'textScore'}},"
"sort: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
cmdObj = fromjson(
"{find: 'testns',"
"projection: {a: {$meta: 'textScore'}},"
"sort: {b: 1}, '$db': 'test'}");
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, ParseCommandAllowMetaSortOnFieldWithoutMetaProject) {
@@ -1134,95 +1077,84 @@ TEST(QueryRequestTest, ParseCommandAllowMetaSortOnFieldWithoutMetaProject) {
"projection: {a: 1},"
"sort: {a: {$meta: 'textScore'}}, '$db': 'test'}");
- bool isExplain = false;
- auto qr = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(cmdObj);
cmdObj = fromjson(
"{find: 'testns',"
"projection: {b: 1},"
"sort: {a: {$meta: 'textScore'}}, '$db': 'test'}");
- qr = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ findCommand = query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, ParseCommandForbidExhaust) {
BSONObj cmdObj = fromjson("{find: 'testns', exhaust: true, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 40415);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 40415);
}
TEST(QueryRequestTest, ParseCommandIsFromFindCommand) {
BSONObj cmdObj = fromjson("{find: 'testns', '$db': 'test'}");
- bool isExplain = false;
- unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain));
+ unique_ptr<FindCommand> findCommand(query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT_FALSE(qr->getNToReturn());
+ ASSERT_FALSE(findCommand->getNtoreturn());
}
TEST(QueryRequestTest, ParseCommandAwaitDataButNotTailable) {
BSONObj cmdObj = fromjson("{find: 'testns', awaitData: true, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::FailedToParse);
}
TEST(QueryRequestTest, ParseCommandFirstFieldNotString) {
BSONObj cmdObj = fromjson("{find: 1, '$db': 'test'}");
- bool isExplain = false;
- ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain),
+ ASSERT_THROWS_CODE(query_request_helper::makeFromFindCommandForTests(cmdObj),
DBException,
ErrorCodes::BadValue);
}
TEST(QueryRequestTest, ParseCommandIgnoreShardVersionField) {
BSONObj cmdObj = fromjson("{find: 'test.testns', shardVersion: 'foo', '$db': 'test'}");
- bool isExplain = false;
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ query_request_helper::makeFromFindCommandForTests(cmdObj);
}
TEST(QueryRequestTest, DefaultQueryParametersCorrect) {
BSONObj cmdObj = fromjson("{find: 'testns', '$db': 'test'}");
- std::unique_ptr<QueryRequest> qr(QueryRequest::makeFromFindCommandForTests(cmdObj, false));
+ std::unique_ptr<FindCommand> findCommand(
+ query_request_helper::makeFromFindCommandForTests(cmdObj));
- ASSERT_FALSE(qr->getSkip());
- ASSERT_FALSE(qr->getLimit());
+ ASSERT_FALSE(findCommand->getSkip());
+ ASSERT_FALSE(findCommand->getLimit());
- ASSERT_FALSE(qr->isSingleBatch());
- ASSERT_FALSE(qr->getNToReturn());
- ASSERT_EQUALS(false, qr->isExplain());
- ASSERT_EQUALS(0, qr->getMaxTimeMS());
- ASSERT_EQUALS(false, qr->returnKey());
- ASSERT_EQUALS(false, qr->showRecordId());
- ASSERT_EQUALS(false, qr->hasReadPref());
- ASSERT_EQUALS(false, qr->isTailable());
- ASSERT_EQUALS(false, qr->isSlaveOk());
- ASSERT_EQUALS(false, qr->isNoCursorTimeout());
- ASSERT_EQUALS(false, qr->isTailableAndAwaitData());
- ASSERT_EQUALS(false, qr->isExhaust());
- ASSERT_EQUALS(false, qr->isAllowPartialResults());
- ASSERT_EQUALS(false, qr->getLegacyRuntimeConstants().has_value());
- ASSERT_EQUALS(false, qr->allowDiskUse());
+ ASSERT_FALSE(findCommand->getSingleBatch());
+ ASSERT_FALSE(findCommand->getNtoreturn());
+ ASSERT_EQUALS(0, findCommand->getMaxTimeMS().value_or(0));
+ ASSERT_EQUALS(false, findCommand->getReturnKey());
+ ASSERT_EQUALS(false, findCommand->getShowRecordId());
+ ASSERT_EQUALS(false, findCommand->getTailable());
+ ASSERT_EQUALS(false, findCommand->getNoCursorTimeout());
+ ASSERT_EQUALS(false, findCommand->getTailable() && findCommand->getAwaitData());
+ ASSERT_EQUALS(false, findCommand->getAllowPartialResults());
+ ASSERT_EQUALS(false, findCommand->getLegacyRuntimeConstants().has_value());
+ ASSERT_EQUALS(false, findCommand->getAllowDiskUse());
}
TEST(QueryRequestTest, ParseCommandAllowDiskUseTrue) {
BSONObj cmdObj = fromjson("{find: 'testns', allowDiskUse: true, '$db': 'test'}");
- const bool isExplain = false;
- auto result = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ auto result = query_request_helper::makeFromFindCommandForTests(cmdObj);
- ASSERT_EQ(true, result->allowDiskUse());
+ ASSERT_EQ(true, result->getAllowDiskUse());
}
TEST(QueryRequestTest, ParseCommandAllowDiskUseFalse) {
BSONObj cmdObj = fromjson("{find: 'testns', allowDiskUse: false, '$db': 'test'}");
- const bool isExplain = false;
- auto result = QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain);
+ auto result = query_request_helper::makeFromFindCommandForTests(cmdObj);
- ASSERT_EQ(false, result->allowDiskUse());
+ ASSERT_EQ(false, result->getAllowDiskUse());
}
//
@@ -1234,9 +1166,8 @@ TEST(QueryRequestTest, ParseFromCommandForbidExtraField) {
"{find: 'testns',"
"foo: {a: 1}, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 40415);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 40415);
}
TEST(QueryRequestTest, ParseFromCommandForbidExtraOption) {
@@ -1244,48 +1175,47 @@ TEST(QueryRequestTest, ParseFromCommandForbidExtraOption) {
"{find: 'testns',"
"foo: true, '$db': 'test'}");
- bool isExplain = false;
ASSERT_THROWS_CODE(
- QueryRequest::makeFromFindCommandForTests(cmdObj, isExplain), DBException, 40415);
+ query_request_helper::makeFromFindCommandForTests(cmdObj), DBException, 40415);
}
TEST(QueryRequestTest, ParseMaxTimeMSStringValueFails) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << "foo");
- ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]));
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << "foo");
+ ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]));
}
TEST(QueryRequestTest, ParseMaxTimeMSNonIntegralValueFails) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << 100.3);
- ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]));
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 100.3);
+ ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]));
}
TEST(QueryRequestTest, ParseMaxTimeMSOutOfRangeDoubleFails) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << 1e200);
- ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]));
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 1e200);
+ ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]));
}
TEST(QueryRequestTest, ParseMaxTimeMSNegativeValueFails) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << -400);
- ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]));
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << -400);
+ ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]));
}
TEST(QueryRequestTest, ParseMaxTimeMSZeroSucceeds) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << 0);
- auto maxTime = parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]);
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 0);
+ auto maxTime = parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]);
ASSERT_OK(maxTime);
ASSERT_EQ(maxTime.getValue(), 0);
}
TEST(QueryRequestTest, ParseMaxTimeMSPositiveInRangeSucceeds) {
- BSONObj maxTimeObj = BSON(QueryRequest::cmdOptionMaxTimeMS << 300);
- auto maxTime = parseMaxTimeMS(maxTimeObj[QueryRequest::cmdOptionMaxTimeMS]);
+ BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 300);
+ auto maxTime = parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]);
ASSERT_OK(maxTime);
ASSERT_EQ(maxTime.getValue(), 300);
}
TEST(QueryRequestTest, ConvertToAggregationSucceeds) {
- QueryRequest qr(testns);
- auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1301,9 +1231,8 @@ TEST(QueryRequestTest, ConvertToAggregationSucceeds) {
}
TEST(QueryRequestTest, ConvertToAggregationOmitsExplain) {
- QueryRequest qr(testns);
- qr.setExplain(true);
- auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1316,113 +1245,113 @@ TEST(QueryRequestTest, ConvertToAggregationOmitsExplain) {
}
TEST(QueryRequestTest, ConvertToAggregationWithHintSucceeds) {
- QueryRequest qr(testns);
- qr.setHint(fromjson("{a_1: -1}"));
- const auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setHint(fromjson("{a_1: -1}"));
+ const auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
auto ar = aggregation_request_helper::parseFromBSONForTests(testns, aggCmd);
ASSERT_OK(ar.getStatus());
- ASSERT_BSONOBJ_EQ(qr.getHint(), ar.getValue().getHint().value_or(BSONObj()));
+ ASSERT_BSONOBJ_EQ(findCommand.getHint(), ar.getValue().getHint().value_or(BSONObj()));
}
TEST(QueryRequestTest, ConvertToAggregationWithMinFails) {
- QueryRequest qr(testns);
- qr.setMin(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setMin(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithMaxFails) {
- QueryRequest qr(testns);
- qr.setMax(fromjson("{a: 1}"));
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setMax(fromjson("{a: 1}"));
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithSingleBatchFieldFails) {
- QueryRequest qr(testns);
- qr.setSingleBatchField(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setSingleBatch(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithSingleBatchFieldAndLimitFails) {
- QueryRequest qr(testns);
- qr.setSingleBatchField(true);
- qr.setLimit(7);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setSingleBatch(true);
+ findCommand.setLimit(7);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithSingleBatchFieldLimitOneSucceeds) {
- QueryRequest qr(testns);
- qr.setSingleBatchField(true);
- qr.setLimit(1);
- ASSERT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setSingleBatch(true);
+ findCommand.setLimit(1);
+ ASSERT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithReturnKeyFails) {
- QueryRequest qr(testns);
- qr.setReturnKey(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setReturnKey(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithShowRecordIdFails) {
- QueryRequest qr(testns);
- qr.setShowRecordId(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setShowRecordId(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithTailableFails) {
- QueryRequest qr(testns);
- qr.setTailableMode(TailableModeEnum::kTailable);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ query_request_helper::setTailableMode(TailableModeEnum::kTailable, &findCommand);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithNoCursorTimeoutFails) {
- QueryRequest qr(testns);
- qr.setNoCursorTimeout(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setNoCursorTimeout(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithAwaitDataFails) {
- QueryRequest qr(testns);
- qr.setTailableMode(TailableModeEnum::kTailableAndAwaitData);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ query_request_helper::setTailableMode(TailableModeEnum::kTailableAndAwaitData, &findCommand);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithAllowPartialResultsFails) {
- QueryRequest qr(testns);
- qr.setAllowPartialResults(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setAllowPartialResults(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithNToReturnFails) {
- QueryRequest qr(testns);
- qr.setNToReturn(7);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setNtoreturn(7);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithRequestResumeTokenFails) {
- QueryRequest qr(testns);
- qr.setRequestResumeToken(true);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ FindCommand findCommand(testns);
+ findCommand.setRequestResumeToken(true);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithResumeAfterFails) {
- QueryRequest qr(testns);
+ FindCommand findCommand(testns);
BSONObj resumeAfter = BSON("$recordId" << 1LL);
- qr.setResumeAfter(resumeAfter);
- ASSERT_NOT_OK(qr.asAggregationCommand());
+ findCommand.setResumeAfter(resumeAfter);
+ ASSERT_NOT_OK(query_request_helper::asAggregationCommand(findCommand));
}
TEST(QueryRequestTest, ConvertToAggregationWithPipeline) {
- QueryRequest qr(testns);
- qr.setFilter(BSON("x" << 1));
- qr.setSort(BSON("y" << -1));
- qr.setLimit(3);
- qr.setSkip(7);
- qr.setProj(BSON("z" << 0));
-
- auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setFilter(BSON("x" << 1));
+ findCommand.setSort(BSON("y" << -1));
+ findCommand.setLimit(3);
+ findCommand.setSkip(7);
+ findCommand.setProjection(BSON("z" << 0));
+
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1447,10 +1376,10 @@ TEST(QueryRequestTest, ConvertToAggregationWithPipeline) {
}
TEST(QueryRequestTest, ConvertToAggregationWithBatchSize) {
- QueryRequest qr(testns);
- qr.setBatchSize(4);
+ FindCommand findCommand(testns);
+ findCommand.setBatchSize(4);
- auto agg = qr.asAggregationCommand();
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1465,10 +1394,10 @@ TEST(QueryRequestTest, ConvertToAggregationWithBatchSize) {
}
TEST(QueryRequestTest, ConvertToAggregationWithMaxTimeMS) {
- QueryRequest qr(testns);
- qr.setMaxTimeMS(9);
+ FindCommand findCommand(testns);
+ findCommand.setMaxTimeMS(9);
- auto agg = qr.asAggregationCommand();
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
const BSONObj cmdObj = agg.getValue();
@@ -1486,9 +1415,9 @@ TEST(QueryRequestTest, ConvertToAggregationWithMaxTimeMS) {
}
TEST(QueryRequestTest, ConvertToAggregationWithCollationSucceeds) {
- QueryRequest qr(testns);
- qr.setCollation(BSON("f" << 1));
- auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setCollation(BSON("f" << 1));
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1504,24 +1433,24 @@ TEST(QueryRequestTest, ConvertToAggregationWithCollationSucceeds) {
}
TEST(QueryRequestTest, ConvertToAggregationWithReadOnceFails) {
- QueryRequest qr(testns);
- qr.setReadOnce(true);
- const auto aggCmd = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setReadOnce(true);
+ const auto aggCmd = query_request_helper::asAggregationCommand(findCommand);
ASSERT_EQ(ErrorCodes::InvalidPipelineOperator, aggCmd.getStatus().code());
}
TEST(QueryRequestTest, ConvertToAggregationWithAllowSpeculativeMajorityReadFails) {
- QueryRequest qr(testns);
- qr.setAllowSpeculativeMajorityRead(true);
- const auto aggCmd = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setAllowSpeculativeMajorityRead(true);
+ const auto aggCmd = query_request_helper::asAggregationCommand(findCommand);
ASSERT_EQ(ErrorCodes::InvalidPipelineOperator, aggCmd.getStatus().code());
}
TEST(QueryRequestTest, ConvertToAggregationWithLegacyRuntimeConstantsSucceeds) {
LegacyRuntimeConstants rtc{Date_t::now(), Timestamp(1, 1)};
- QueryRequest qr(testns);
- qr.setLegacyRuntimeConstants(rtc);
- auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setLegacyRuntimeConstants(rtc);
+ auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg);
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1533,9 +1462,9 @@ TEST(QueryRequestTest, ConvertToAggregationWithLegacyRuntimeConstantsSucceeds) {
}
TEST(QueryRequestTest, ConvertToAggregationWithAllowDiskUseTrueSucceeds) {
- QueryRequest qr(testns);
- qr.setAllowDiskUse(true);
- const auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setAllowDiskUse(true);
+ const auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg.getStatus());
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1545,9 +1474,9 @@ TEST(QueryRequestTest, ConvertToAggregationWithAllowDiskUseTrueSucceeds) {
}
TEST(QueryRequestTest, ConvertToAggregationWithAllowDiskUseFalseSucceeds) {
- QueryRequest qr(testns);
- qr.setAllowDiskUse(false);
- const auto agg = qr.asAggregationCommand();
+ FindCommand findCommand(testns);
+ findCommand.setAllowDiskUse(false);
+ const auto agg = query_request_helper::asAggregationCommand(findCommand);
ASSERT_OK(agg.getStatus());
auto aggCmd = OpMsgRequest::fromDBAndBody(testns.db(), agg.getValue()).body;
@@ -1557,21 +1486,21 @@ TEST(QueryRequestTest, ConvertToAggregationWithAllowDiskUseFalseSucceeds) {
}
TEST(QueryRequestTest, ConvertToFindWithAllowDiskUseTrueSucceeds) {
- QueryRequest qr(testns);
- qr.setAllowDiskUse(true);
- const auto findCmd = qr.asFindCommand();
+ FindCommand findCommand(testns);
+ findCommand.setAllowDiskUse(true);
+ const auto findCmd = findCommand.toBSON(BSONObj());
- BSONElement elem = findCmd[QueryRequest::kAllowDiskUseField];
+ BSONElement elem = findCmd[FindCommand::kAllowDiskUseFieldName];
ASSERT_EQ(true, elem.isBoolean());
ASSERT_EQ(true, elem.Bool());
}
TEST(QueryRequestTest, ConvertToFindWithAllowDiskUseFalseSucceeds) {
- QueryRequest qr(testns);
- qr.setAllowDiskUse(false);
- const auto findCmd = qr.asFindCommand();
+ FindCommand findCommand(testns);
+ findCommand.setAllowDiskUse(false);
+ const auto findCmd = findCommand.toBSON(BSONObj());
- ASSERT_FALSE(findCmd[QueryRequest::kAllowDiskUseField].booleanSafe());
+ ASSERT_FALSE(findCmd[FindCommand::kAllowDiskUseFieldName].booleanSafe());
}
TEST(QueryRequestTest, ParseFromLegacyQuery) {
@@ -1586,28 +1515,25 @@ TEST(QueryRequestTest, ParseFromLegacyQuery) {
$min: {x: 'min'},
$max: {x: 'max'}
})");
- unique_ptr<QueryRequest> qr(
- std::move(QueryRequest::fromLegacyQuery(
- nss, queryObj, BSON("proj" << 1), kSkip, kNToReturn, QueryOption_Exhaust)
- .getValue()));
-
- ASSERT_EQ(qr->nss(), nss);
- ASSERT_BSONOBJ_EQ(qr->getFilter(), fromjson("{query: 1}"));
- ASSERT_BSONOBJ_EQ(qr->getProj(), fromjson("{proj: 1}"));
- ASSERT_BSONOBJ_EQ(qr->getSort(), fromjson("{sort: 1}"));
- ASSERT_BSONOBJ_EQ(qr->getHint(), fromjson("{hint: 1}"));
- ASSERT_BSONOBJ_EQ(qr->getMin(), fromjson("{x: 'min'}"));
- ASSERT_BSONOBJ_EQ(qr->getMax(), fromjson("{x: 'max'}"));
- ASSERT_EQ(qr->getSkip(), boost::optional<int64_t>(kSkip));
- ASSERT_EQ(qr->getNToReturn(), boost::optional<int64_t>(kNToReturn));
- ASSERT_EQ(qr->isSingleBatch(), false);
- ASSERT_EQ(qr->isExplain(), false);
- ASSERT_EQ(qr->isSlaveOk(), false);
- ASSERT_EQ(qr->isNoCursorTimeout(), false);
- ASSERT_EQ(qr->isTailable(), false);
- ASSERT_EQ(qr->isExhaust(), true);
- ASSERT_EQ(qr->isAllowPartialResults(), false);
- ASSERT_EQ(qr->getOptions(), QueryOption_Exhaust);
+
+ bool explain = false;
+ unique_ptr<FindCommand> findCommand(assertGet(query_request_helper::fromLegacyQuery(
+ nss, queryObj, BSON("proj" << 1), kSkip, kNToReturn, QueryOption_Exhaust, &explain)));
+
+ ASSERT_EQ(*findCommand->getNamespaceOrUUID().nss(), nss);
+ ASSERT_EQ(explain, false);
+ ASSERT_BSONOBJ_EQ(findCommand->getFilter(), fromjson("{query: 1}"));
+ ASSERT_BSONOBJ_EQ(findCommand->getProjection(), fromjson("{proj: 1}"));
+ ASSERT_BSONOBJ_EQ(findCommand->getSort(), fromjson("{sort: 1}"));
+ ASSERT_BSONOBJ_EQ(findCommand->getHint(), fromjson("{hint: 1}"));
+ ASSERT_BSONOBJ_EQ(findCommand->getMin(), fromjson("{x: 'min'}"));
+ ASSERT_BSONOBJ_EQ(findCommand->getMax(), fromjson("{x: 'max'}"));
+ ASSERT_EQ(findCommand->getSkip(), boost::optional<int64_t>(kSkip));
+ ASSERT_EQ(findCommand->getNtoreturn(), boost::optional<int64_t>(kNToReturn));
+ ASSERT_EQ(findCommand->getSingleBatch(), false);
+ ASSERT_EQ(findCommand->getNoCursorTimeout(), false);
+ ASSERT_EQ(findCommand->getTailable(), false);
+ ASSERT_EQ(findCommand->getAllowPartialResults(), false);
}
TEST(QueryRequestTest, ParseFromLegacyQueryOplogReplayFlagAllowed) {
@@ -1620,13 +1546,16 @@ TEST(QueryRequestTest, ParseFromLegacyQueryOplogReplayFlagAllowed) {
// Test that parsing succeeds even if the oplog replay bit is set in the OP_QUERY message. This
// flag may be set by old clients.
auto options = QueryOption_OplogReplay_DEPRECATED;
- auto qr =
- QueryRequest::fromLegacyQuery(nss, queryObj, projectionObj, nToSkip, nToReturn, options);
- ASSERT_OK(qr.getStatus());
+ bool explain = false;
+ unique_ptr<FindCommand> findCommand(assertGet(query_request_helper::fromLegacyQuery(
+ nss, queryObj, projectionObj, nToSkip, nToReturn, options, &explain)));
- // Verify that if we reserialize the QueryRequest as a find command, the 'oplogReplay' field
+ // Verify that if we reserialize the find command, the 'oplogReplay' field
// does not appear.
- auto reserialized = qr.getValue()->asFindCommand();
+ BSONObjBuilder bob;
+ findCommand->serialize(BSONObj(), &bob);
+ auto reserialized = bob.obj();
+
ASSERT_BSONOBJ_EQ(reserialized,
BSON("find"
<< "testns"
@@ -1639,11 +1568,12 @@ TEST(QueryRequestTest, ParseFromLegacyQueryUnwrapped) {
foo: 1
})");
const NamespaceString nss("test.testns");
- unique_ptr<QueryRequest> qr(assertGet(
- QueryRequest::fromLegacyQuery(nss, queryObj, BSONObj(), 0, 0, QueryOption_Exhaust)));
+ bool explain = false;
+ unique_ptr<FindCommand> findCommand(assertGet(query_request_helper::fromLegacyQuery(
+ nss, queryObj, BSONObj(), 0, 0, QueryOption_Exhaust, &explain)));
- ASSERT_EQ(qr->nss(), nss);
- ASSERT_BSONOBJ_EQ(qr->getFilter(), fromjson("{foo: 1}"));
+ ASSERT_EQ(*findCommand->getNamespaceOrUUID().nss(), nss);
+ ASSERT_BSONOBJ_EQ(findCommand->getFilter(), fromjson("{foo: 1}"));
}
TEST(QueryRequestTest, ParseFromLegacyQueryTooNegativeNToReturn) {
@@ -1652,10 +1582,15 @@ TEST(QueryRequestTest, ParseFromLegacyQueryTooNegativeNToReturn) {
})");
const NamespaceString nss("test.testns");
- ASSERT_NOT_OK(
- QueryRequest::fromLegacyQuery(
- nss, queryObj, BSONObj(), 0, std::numeric_limits<int>::min(), QueryOption_Exhaust)
- .getStatus());
+ bool explain = false;
+ ASSERT_NOT_OK(query_request_helper::fromLegacyQuery(nss,
+ queryObj,
+ BSONObj(),
+ 0,
+ std::numeric_limits<int>::min(),
+ QueryOption_Exhaust,
+ &explain)
+ .getStatus());
}
class QueryRequestTest : public ServiceContextTest {};
@@ -1665,11 +1600,11 @@ TEST_F(QueryRequestTest, ParseFromUUID) {
NamespaceStringOrUUID nssOrUUID("test", uuid);
- QueryRequest qr(nssOrUUID);
+ FindCommand findCommand(nssOrUUID);
const NamespaceString nss("test.testns");
// Ensure a call to refreshNSS succeeds.
- qr.refreshNSS(nss);
- ASSERT_EQ(nss, qr.nss());
+ query_request_helper::refreshNSS(nss, &findCommand);
+ ASSERT_EQ(nss, *findCommand.getNamespaceOrUUID().nss());
}
} // namespace
diff --git a/src/mongo/db/query/query_settings.cpp b/src/mongo/db/query/query_settings.cpp
index 5060d6d9ac8..d3552edd3c0 100644
--- a/src/mongo/db/query/query_settings.cpp
+++ b/src/mongo/db/query/query_settings.cpp
@@ -101,10 +101,10 @@ std::vector<AllowedIndexEntry> QuerySettings::getAllAllowedIndices() const {
void QuerySettings::setAllowedIndices(const CanonicalQuery& canonicalQuery,
const BSONObjSet& indexKeyPatterns,
const stdx::unordered_set<std::string>& indexNames) {
- const QueryRequest& qr = canonicalQuery.getQueryRequest();
- const BSONObj& query = qr.getFilter();
- const BSONObj& sort = qr.getSort();
- const BSONObj& projection = qr.getProj();
+ const FindCommand& findCommand = canonicalQuery.getFindCommand();
+ const BSONObj& query = findCommand.getFilter();
+ const BSONObj& sort = findCommand.getSort();
+ const BSONObj& projection = findCommand.getProjection();
const auto key = canonicalQuery.encodeKey();
const BSONObj collation =
canonicalQuery.getCollator() ? canonicalQuery.getCollator()->getSpec().toBSON() : BSONObj();
diff --git a/src/mongo/db/query/sbe_stage_builder.cpp b/src/mongo/db/query/sbe_stage_builder.cpp
index fc041266768..c7da41d5daa 100644
--- a/src/mongo/db/query/sbe_stage_builder.cpp
+++ b/src/mongo/db/query/sbe_stage_builder.cpp
@@ -1416,7 +1416,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> SlotBasedStageBuilder
case STAGE_COLLSCAN:
case STAGE_LIMIT:
case STAGE_SKIP:
- if (_cq.getQueryRequest().isTailable() &&
+ if (_cq.getFindCommand().getTailable() &&
!reqs.getIsBuildingUnionForTailableCollScan()) {
auto childReqs = reqs;
childReqs.setIsBuildingUnionForTailableCollScan(true);
diff --git a/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp b/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp
index d832a3e30b6..fad3a4cd63a 100644
--- a/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp
+++ b/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp
@@ -49,9 +49,10 @@ SbeStageBuilderTestFixture::buildPlanStage(
std::unique_ptr<QuerySolution> querySolution,
bool hasRecordId,
std::unique_ptr<ShardFiltererFactoryInterface> shardFiltererInterface) {
- auto qr = std::make_unique<QueryRequest>(_nss);
+ auto findCommand = std::make_unique<FindCommand>(_nss);
const boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContextForTest(_nss));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr), expCtx);
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, expCtx);
ASSERT_OK(statusWithCQ.getStatus());
stage_builder::SlotBasedStageBuilder builder{opCtx(),
diff --git a/src/mongo/db/s/config/config_server_test_fixture.cpp b/src/mongo/db/s/config/config_server_test_fixture.cpp
index a2fba05a49b..228ac592d20 100644
--- a/src/mongo/db/s/config/config_server_test_fixture.cpp
+++ b/src/mongo/db/s/config/config_server_test_fixture.cpp
@@ -45,7 +45,7 @@
#include "mongo/db/op_observer.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/query/cursor_response.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/repl/repl_settings.h"
diff --git a/src/mongo/db/s/config/sharding_catalog_manager.cpp b/src/mongo/db/s/config/sharding_catalog_manager.cpp
index 271fc1d52b8..ff00b91fbeb 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/error_labels.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/write_ops.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/s/balancer/type_migration.h"
#include "mongo/db/s/type_lockpings.h"
#include "mongo/db/s/type_locks.h"
@@ -101,15 +101,14 @@ OpMsg runCommandInLocalTxn(OperationContext* opCtx,
void startTransactionWithNoopFind(OperationContext* opCtx,
const NamespaceString& nss,
TxnNumber txnNumber) {
- BSONObjBuilder findCmdBuilder;
- QueryRequest qr(nss);
- qr.setBatchSize(0);
- qr.setSingleBatchField(true);
- qr.asFindCommand(&findCmdBuilder);
-
- auto res = runCommandInLocalTxn(
- opCtx, nss.db(), true /*startTransaction*/, txnNumber, findCmdBuilder.done())
- .body;
+ FindCommand findCommand(nss);
+ findCommand.setBatchSize(0);
+ findCommand.setSingleBatch(true);
+
+ auto res =
+ runCommandInLocalTxn(
+ opCtx, nss.db(), true /*startTransaction*/, txnNumber, findCommand.toBSON(BSONObj()))
+ .body;
uassertStatusOK(getStatusFromCommandResult(res));
}
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_create_database_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_create_database_test.cpp
index 8b213721ba5..2d0c3ea0b36 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_create_database_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_create_database_test.cpp
@@ -34,7 +34,7 @@
#include "mongo/client/remote_command_targeter_factory_mock.h"
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/commands.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_enable_sharding_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_enable_sharding_test.cpp
index 6a09a6f1358..ae41929f63e 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_enable_sharding_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_enable_sharding_test.cpp
@@ -34,7 +34,7 @@
#include "mongo/client/remote_command_targeter_factory_mock.h"
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/commands.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
diff --git a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
index 4be972ee221..947c9834139 100644
--- a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
+++ b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
@@ -49,7 +49,7 @@
#include "mongo/db/pipeline/document_source_match.h"
#include "mongo/db/pipeline/document_source_replace_root.h"
#include "mongo/db/pipeline/sharded_agg_helpers.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/s/resharding/resharding_server_parameters_gen.h"
#include "mongo/db/s/resharding_util.h"
#include "mongo/db/service_context.h"
@@ -218,11 +218,12 @@ Value ReshardingCollectionCloner::_findHighestInsertedId(OperationContext* opCtx
<< "' did not already exist",
outputColl);
- auto qr = std::make_unique<QueryRequest>(_outputNss);
- qr->setLimit(1);
- qr->setSort(BSON("_id" << -1));
+ auto findCommand = std::make_unique<FindCommand>(_outputNss);
+ findCommand->setLimit(1);
+ findCommand->setSort(BSON("_id" << -1));
- auto recordId = Helpers::findOne(opCtx, *outputColl, std::move(qr), true /* requireIndex */);
+ auto recordId =
+ Helpers::findOne(opCtx, *outputColl, std::move(findCommand), true /* requireIndex */);
if (recordId.isNull()) {
return Value{};
}
diff --git a/src/mongo/db/s/sharding_mongod_test_fixture.cpp b/src/mongo/db/s/sharding_mongod_test_fixture.cpp
index 7de0b0b5825..11529d01e58 100644
--- a/src/mongo/db/s/sharding_mongod_test_fixture.cpp
+++ b/src/mongo/db/s/sharding_mongod_test_fixture.cpp
@@ -43,7 +43,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/op_observer_registry.h"
#include "mongo/db/query/cursor_response.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/drop_pending_collection_reaper.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/read_concern_args.h"
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index e918fb3d592..79466de4bb5 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -1343,9 +1343,9 @@ void ExecCommandDatabase::_initiateCommand() {
StringMap<int> topLevelFields;
for (auto&& element : request.body) {
StringData fieldName = element.fieldNameStringData();
- if (fieldName == QueryRequest::cmdOptionMaxTimeMS) {
+ if (fieldName == query_request_helper::cmdOptionMaxTimeMS) {
cmdOptionMaxTimeMSField = element;
- } else if (fieldName == QueryRequest::kMaxTimeMSOpOnlyField) {
+ } else if (fieldName == query_request_helper::kMaxTimeMSOpOnlyField) {
uassert(ErrorCodes::InvalidOptions,
"Can not specify maxTimeMSOpOnly for non internal clients",
_isInternalClient());
@@ -1356,7 +1356,7 @@ void ExecCommandDatabase::_initiateCommand() {
helpField = element;
} else if (fieldName == "comment") {
opCtx->setComment(element.wrap());
- } else if (fieldName == QueryRequest::queryOptionMaxTimeMS) {
+ } else if (fieldName == query_request_helper::queryOptionMaxTimeMS) {
uasserted(ErrorCodes::InvalidOptions,
"no such command option $maxTimeMs; use maxTimeMS instead");
}
diff --git a/src/mongo/db/transaction_history_iterator.cpp b/src/mongo/db/transaction_history_iterator.cpp
index e0584763df7..70f38a7ed01 100644
--- a/src/mongo/db/transaction_history_iterator.cpp
+++ b/src/mongo/db/transaction_history_iterator.cpp
@@ -35,7 +35,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/query/get_executor.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/local_oplog_info.h"
#include "mongo/db/repl/oplog_entry.h"
#include "mongo/db/transaction_history_iterator.h"
@@ -56,18 +56,19 @@ BSONObj findOneOplogEntry(OperationContext* opCtx,
BSONObj oplogBSON;
invariant(!opTime.isNull());
- auto qr = std::make_unique<QueryRequest>(NamespaceString::kRsOplogNamespace);
- qr->setFilter(opTime.asQuery());
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString::kRsOplogNamespace);
+ findCommand->setFilter(opTime.asQuery());
if (prevOpOnly) {
- qr->setProj(
+ findCommand->setProjection(
BSON("_id" << 0 << repl::OplogEntry::kPrevWriteOpTimeInTransactionFieldName << 1LL));
}
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ = CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kBanAllSpecialFeatures);
diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp
index 993af2e55bf..93be4678360 100644
--- a/src/mongo/db/ttl.cpp
+++ b/src/mongo/db/ttl.cpp
@@ -366,9 +366,9 @@ private:
const char* keyFieldName = key.firstElement().fieldName();
BSONObj query =
BSON(keyFieldName << BSON("$gte" << kDawnOfTime << "$lte" << expirationTime));
- auto qr = std::make_unique<QueryRequest>(collectionNSS);
- qr->setFilter(query);
- auto canonicalQuery = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(collectionNSS);
+ findCommand->setFilter(query);
+ auto canonicalQuery = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
invariant(canonicalQuery.getStatus());
auto params = std::make_unique<DeleteStageParams>();
diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp
index 1c402f2a24d..156830388a8 100644
--- a/src/mongo/db/update/update_driver.cpp
+++ b/src/mongo/db/update/update_driver.cpp
@@ -195,14 +195,15 @@ Status UpdateDriver::populateDocumentWithQueryFields(OperationContext* opCtx,
// We canonicalize the query to collapse $and/$or, and the namespace is not needed. Also,
// because this is for the upsert case, where we insert a new document if one was not found, the
// $where/$text clauses do not make sense, hence empty ExtensionsCallback.
- auto qr = std::make_unique<QueryRequest>(NamespaceString(""));
- qr->setFilter(query);
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString(""));
+ findCommand->setFilter(query);
const boost::intrusive_ptr<ExpressionContext> expCtx;
// $expr is not allowed in the query for an upsert, since it is not clear what the equality
// extraction behavior for $expr should be.
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures &
diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp
index 60cb1965eba..811e8bf6882 100644
--- a/src/mongo/dbtests/documentsourcetests.cpp
+++ b/src/mongo/dbtests/documentsourcetests.cpp
@@ -93,11 +93,11 @@ protected:
dbtests::WriteContextForTests ctx(opCtx(), nss.ns());
_coll = ctx.getCollection();
- auto qr = std::make_unique<QueryRequest>(nss);
+ auto findCommand = std::make_unique<FindCommand>(nss);
if (hint) {
- qr->setHint(*hint);
+ findCommand->setHint(*hint);
}
- auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(qr)));
+ auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
auto exec = uassertStatusOK(getExecutor(opCtx(),
&_coll,
@@ -312,11 +312,12 @@ TEST_F(DocumentSourceCursorTest, TailableAwaitDataCursorShouldErrorAfterTimeout)
collScanParams,
workingSet.get(),
matchExpression.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(filter);
- queryRequest->setTailableMode(TailableModeEnum::kTailableAndAwaitData);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
+ query_request_helper::setTailableMode(TailableModeEnum::kTailableAndAwaitData,
+ findCommand.get());
auto canonicalQuery = unittest::assertGet(
- CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest), nullptr));
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, nullptr));
auto planExecutor =
uassertStatusOK(plan_executor_factory::make(std::move(canonicalQuery),
std::move(workingSet),
@@ -355,10 +356,10 @@ TEST_F(DocumentSourceCursorTest, NonAwaitDataCursorShouldErrorAfterTimeout) {
collScanParams,
workingSet.get(),
matchExpression.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(filter);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
auto canonicalQuery = unittest::assertGet(
- CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest), nullptr));
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, nullptr));
auto planExecutor =
uassertStatusOK(plan_executor_factory::make(std::move(canonicalQuery),
std::move(workingSet),
@@ -407,11 +408,12 @@ TEST_F(DocumentSourceCursorTest, TailableAwaitDataCursorShouldErrorAfterBeingKil
collScanParams,
workingSet.get(),
matchExpression.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(filter);
- queryRequest->setTailableMode(TailableModeEnum::kTailableAndAwaitData);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
+ query_request_helper::setTailableMode(TailableModeEnum::kTailableAndAwaitData,
+ findCommand.get());
auto canonicalQuery = unittest::assertGet(
- CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest), nullptr));
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, nullptr));
auto planExecutor = uassertStatusOK(
plan_executor_factory::make(std::move(canonicalQuery),
std::move(workingSet),
@@ -449,10 +451,10 @@ TEST_F(DocumentSourceCursorTest, NormalCursorShouldErrorAfterBeingKilled) {
collScanParams,
workingSet.get(),
matchExpression.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(filter);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
auto canonicalQuery = unittest::assertGet(
- CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest), nullptr));
+ CanonicalQuery::canonicalize(opCtx(), std::move(findCommand), false, nullptr));
auto planExecutor = uassertStatusOK(
plan_executor_factory::make(std::move(canonicalQuery),
std::move(workingSet),
diff --git a/src/mongo/dbtests/plan_executor_invalidation_test.cpp b/src/mongo/dbtests/plan_executor_invalidation_test.cpp
index a3a92ab4854..e77c5d59c1a 100644
--- a/src/mongo/dbtests/plan_executor_invalidation_test.cpp
+++ b/src/mongo/dbtests/plan_executor_invalidation_test.cpp
@@ -81,8 +81,8 @@ public:
new CollectionScan(_expCtx.get(), collection(), params, ws.get(), nullptr));
// Create a plan executor to hold it
- auto qr = std::make_unique<QueryRequest>(nss);
- auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp
index 79f977d1409..461fc617b12 100644
--- a/src/mongo/dbtests/plan_ranking.cpp
+++ b/src/mongo/dbtests/plan_ranking.cpp
@@ -230,10 +230,10 @@ public:
addIndex(BSON("d" << 1));
// Query: find({a: 1}).sort({d: 1})
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 1));
- qr->setSort(BSON("d" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 1));
+ findCommand->setSort(BSON("d" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(cq);
@@ -287,9 +287,9 @@ public:
// Run the query {a:4, b:1}.
{
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 100 << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 100 << "b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
cq = std::move(statusWithCQ.getValue());
ASSERT(cq.get());
@@ -306,9 +306,9 @@ public:
// And run the same query again.
{
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 100 << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 100 << "b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
cq = std::move(statusWithCQ.getValue());
}
@@ -341,9 +341,9 @@ public:
addIndex(BSON("b" << 1));
// Run the query {a:1, b:{$gt:1}.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 1 << "b" << BSON("$gt" << 1)));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 1 << "b" << BSON("$gt" << 1)));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -381,10 +381,10 @@ public:
addIndex(BSON("a" << 1 << "b" << 1));
// Query for a==27 with projection that wants 'a' and 'b'.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 27));
- qr->setProj(BSON("_id" << 0 << "a" << 1 << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 27));
+ findCommand->setProjection(BSON("_id" << 0 << "a" << 1 << "b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -416,9 +416,9 @@ public:
addIndex(BSON("b" << 1));
// There is no data that matches this query but we don't know that until EOF.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 1 << "b" << 1 << "c" << 99));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 1 << "b" << 1 << "c" << 99));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -453,11 +453,11 @@ public:
// There is no data that matches this query ({a:2}). Both scans will hit EOF before
// returning any data.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 2));
- qr->setProj(BSON("_id" << 0 << "a" << 1 << "b" << 1));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 2));
+ findCommand->setProjection(BSON("_id" << 0 << "a" << 1 << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -488,9 +488,9 @@ public:
addIndex(BSON("b" << 1));
// Run the query {a:N+1, b:1}. (No such document.)
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << N + 1 << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << N + 1 << "b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -524,9 +524,9 @@ public:
addIndex(BSON("b" << 1));
// Run the query {a:N+1, b:1}. (No such document.)
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << BSON("$gte" << N + 1) << "b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << BSON("$gte" << N + 1) << "b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -553,10 +553,10 @@ public:
// Run a query with a sort. The blocking sort won't produce any data during the
// evaluation period.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("_id" << BSON("$gte" << 20 << "$lte" << 200)));
- qr->setSort(BSON("c" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("_id" << BSON("$gte" << 20 << "$lte" << 200)));
+ findCommand->setSort(BSON("c" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -583,9 +583,9 @@ public:
}
// Look for A Space Odyssey.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("foo" << 2001));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("foo" << 2001));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -616,10 +616,10 @@ public:
addIndex(BSON("d" << 1 << "e" << 1));
// Query: find({a: 1}).sort({d: 1})
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 1));
- qr->setSort(BSON("d" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 1));
+ findCommand->setSort(BSON("d" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -654,9 +654,9 @@ public:
// Solutions using either 'a' or 'b' will take a long time to start producing
// results. However, an index scan on 'b' will start producing results sooner
// than an index scan on 'a'.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{a: 1, b: 1, c: {$gte: 5000}}"));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{a: 1, b: 1, c: {$gte: 5000}}"));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -686,9 +686,9 @@ public:
addIndex(BSON("b" << 1 << "c" << 1));
addIndex(BSON("a" << 1));
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{a: 9, b: {$ne: 10}, c: 9}"));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{a: 9, b: {$ne: 10}, c: 9}"));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
diff --git a/src/mongo/dbtests/query_plan_executor.cpp b/src/mongo/dbtests/query_plan_executor.cpp
index 4d027200708..570a0cc37b2 100644
--- a/src/mongo/dbtests/query_plan_executor.cpp
+++ b/src/mongo/dbtests/query_plan_executor.cpp
@@ -106,10 +106,10 @@ public:
unique_ptr<WorkingSet> ws(new WorkingSet());
// Canonicalize the query.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(filterObj);
- qr->setTailableMode(tailableMode);
- auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filterObj);
+ query_request_helper::setTailableMode(tailableMode, findCommand.get());
+ auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
verify(nullptr != cq.get());
@@ -155,8 +155,8 @@ public:
unique_ptr<PlanStage> root =
std::make_unique<FetchStage>(_expCtx.get(), ws.get(), std::move(ixscan), nullptr, coll);
- auto qr = std::make_unique<QueryRequest>(nss);
- auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
verify(nullptr != cq.get());
diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp
index 4625bd6ebf9..f79bcb15763 100644
--- a/src/mongo/dbtests/query_stage_cached_plan.cpp
+++ b/src/mongo/dbtests/query_stage_cached_plan.cpp
@@ -60,9 +60,9 @@ namespace {
std::unique_ptr<CanonicalQuery> canonicalQueryFromFilterObj(OperationContext* opCtx,
const NamespaceString& nss,
BSONObj filter) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(filter);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
uassertStatusOK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -187,9 +187,9 @@ TEST_F(QueryStageCachedPlan, QueryStageCachedPlanFailureMemoryLimitExceeded) {
ASSERT(collection);
// Query can be answered by either index on "a" or index on "b".
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{a: {$gte: 8}, b: 1}"));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{a: {$gte: 8}, b: 1}"));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -237,9 +237,9 @@ TEST_F(QueryStageCachedPlan, QueryStageCachedPlanHitMaxWorks) {
ASSERT(collection);
// Query can be answered by either index on "a" or index on "b".
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{a: {$gte: 8}, b: 1}"));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{a: {$gte: 8}, b: 1}"));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -448,8 +448,8 @@ TEST_F(QueryStageCachedPlan, ThrowsOnYieldRecoveryWhenIndexIsDroppedBeforePlanSe
ASSERT(collection);
// Query can be answered by either index on "a" or index on "b".
- auto qr = std::make_unique<QueryRequest>(nss);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -492,8 +492,8 @@ TEST_F(QueryStageCachedPlan, DoesNotThrowOnYieldRecoveryWhenIndexIsDroppedAferPl
ASSERT(collection);
// Query can be answered by either index on "a" or index on "b".
- auto qr = std::make_unique<QueryRequest>(nss);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/dbtests/query_stage_delete.cpp b/src/mongo/dbtests/query_stage_delete.cpp
index 03b7834e079..93fbd082916 100644
--- a/src/mongo/dbtests/query_stage_delete.cpp
+++ b/src/mongo/dbtests/query_stage_delete.cpp
@@ -104,9 +104,9 @@ public:
}
unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp
index f4300805bd2..5ef147ed590 100644
--- a/src/mongo/dbtests/query_stage_multiplan.cpp
+++ b/src/mongo/dbtests/query_stage_multiplan.cpp
@@ -128,9 +128,9 @@ protected:
std::unique_ptr<CanonicalQuery> makeCanonicalQuery(OperationContext* opCtx,
NamespaceString nss,
BSONObj filter) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(filter);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filter);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(cq);
@@ -374,10 +374,10 @@ TEST_F(QueryStageMultiPlanTest, MPSBackupPlan) {
AutoGetCollectionForReadCommand collection(_opCtx.get(), nss);
// Query for both 'a' and 'b' and sort on 'b'.
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("a" << 1 << "b" << 1));
- qr->setSort(BSON("b" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("a" << 1 << "b" << 1));
+ findCommand->setSort(BSON("b" << 1));
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(nullptr != cq.get());
@@ -486,9 +486,9 @@ TEST_F(QueryStageMultiPlanTest, MPSExplainAllPlans) {
AutoGetCollectionForReadCommand ctx(_opCtx.get(), nss);
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("x" << 1));
- auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("x" << 1));
+ auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
unique_ptr<MultiPlanStage> mps =
std::make_unique<MultiPlanStage>(_expCtx.get(), ctx.getCollection(), cq.get());
@@ -558,9 +558,9 @@ TEST_F(QueryStageMultiPlanTest, MPSSummaryStats) {
const CollectionPtr& coll = ctx.getCollection();
// Create the executor (Matching all documents).
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(BSON("foo" << BSON("$gte" << 0)));
- auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("foo" << BSON("$gte" << 0)));
+ auto cq = uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
auto exec = uassertStatusOK(
getExecutor(opCtx(), &coll, std::move(cq), PlanYieldPolicy::YieldPolicy::NO_YIELD, 0));
@@ -611,10 +611,10 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlannin
getCollScanPlan(_expCtx.get(), coll.getCollection(), sharedWs.get(), filter.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(filterObj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(filterObj);
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
MultiPlanStage multiPlanStage(
_expCtx.get(), coll.getCollection(), canonicalQuery.get(), PlanCachingMode::NeverCache);
multiPlanStage.addPlan(createQuerySolution(), std::move(ixScanRoot), sharedWs.get());
@@ -651,10 +651,10 @@ TEST_F(QueryStageMultiPlanTest, ShouldReportErrorIfKilledDuringPlanning) {
unique_ptr<PlanStage> collScanRoot =
getCollScanPlan(_expCtx.get(), coll.getCollection(), sharedWs.get(), filter.get());
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("foo" << BSON("$gte" << 0)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("foo" << BSON("$gte" << 0)));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
MultiPlanStage multiPlanStage(
_expCtx.get(), coll.getCollection(), canonicalQuery.get(), PlanCachingMode::NeverCache);
multiPlanStage.addPlan(createQuerySolution(), std::move(ixScanRoot), sharedWs.get());
@@ -694,11 +694,11 @@ TEST_F(QueryStageMultiPlanTest, AddsContextDuringException) {
insert(BSON("foo" << 10));
AutoGetCollectionForReadCommand ctx(_opCtx.get(), nss);
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("fake"
- << "query"));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("fake"
+ << "query"));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
MultiPlanStage multiPlanStage(
_expCtx.get(), ctx.getCollection(), canonicalQuery.get(), PlanCachingMode::NeverCache);
unique_ptr<WorkingSet> sharedWs(new WorkingSet());
diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp
index afbfc280c15..1a63e655cf9 100644
--- a/src/mongo/dbtests/query_stage_subplan.cpp
+++ b/src/mongo/dbtests/query_stage_subplan.cpp
@@ -97,11 +97,13 @@ protected:
bool isExplain = false;
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody("test", cmdObj).body;
- auto qr = QueryRequest::makeFromFindCommandForTests(cmd, isExplain, NamespaceString());
+ auto findCommand =
+ query_request_helper::makeFromFindCommandForTests(cmd, NamespaceString());
auto cq = unittest::assertGet(
CanonicalQuery::canonicalize(opCtx(),
- std::move(qr),
+ std::move(findCommand),
+ isExplain,
expCtx(),
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures));
@@ -135,9 +137,9 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanGeo2dOr) {
"{$or: [{a: {$geoWithin: {$centerSphere: [[0,0],10]}}},"
"{a: {$geoWithin: {$centerSphere: [[1,1],10]}}}]}");
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -172,9 +174,9 @@ void assertSubplanFromCache(QueryStageSubplanTest* test, const dbtests::WriteCon
CollectionPtr collection = ctx.getCollection();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(test->opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(test->opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -256,9 +258,9 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheZeroResults) {
CollectionPtr collection = ctx.getCollection();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -312,9 +314,9 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanDontCacheTies) {
CollectionPtr collection = ctx.getCollection();
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(opCtx(), std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -484,10 +486,10 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanPlanRootedOrNE) {
insert(BSON("_id" << 3 << "a" << 3));
insert(BSON("_id" << 4));
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(fromjson("{$or: [{a: 1}, {a: {$ne:1}}]}"));
- qr->setSort(BSON("d" << 1));
- auto cq = unittest::assertGet(CanonicalQuery::canonicalize(opCtx(), std::move(qr)));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(fromjson("{$or: [{a: 1}, {a: {$ne:1}}]}"));
+ findCommand->setSort(BSON("d" << 1));
+ auto cq = unittest::assertGet(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
CollectionPtr collection = ctx.getCollection();
@@ -517,10 +519,10 @@ TEST_F(QueryStageSubplanTest, QueryStageSubplanPlanRootedOrNE) {
TEST_F(QueryStageSubplanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlanning) {
dbtests::WriteContextForTests ctx(opCtx(), nss.ns());
// Build a query with a rooted $or.
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
// Add 4 indices: 2 for each predicate to choose from.
addIndex(BSON("p1" << 1 << "opt1" << 1));
@@ -550,10 +552,10 @@ TEST_F(QueryStageSubplanTest, ShouldReportErrorIfExceedsTimeLimitDuringPlanning)
TEST_F(QueryStageSubplanTest, ShouldReportErrorIfKilledDuringPlanning) {
dbtests::WriteContextForTests ctx(opCtx(), nss.ns());
// Build a query with a rooted $or.
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
// Add 4 indices: 2 for each predicate to choose from.
addIndex(BSON("p1" << 1 << "opt1" << 1));
@@ -587,10 +589,10 @@ TEST_F(QueryStageSubplanTest, ShouldThrowOnRestoreIfIndexDroppedBeforePlanSelect
}
// Build a query with a rooted $or.
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
boost::optional<AutoGetCollectionForReadCommand> collLock;
collLock.emplace(opCtx(), nss);
@@ -633,10 +635,10 @@ TEST_F(QueryStageSubplanTest, ShouldNotThrowOnRestoreIfIndexDroppedAfterPlanSele
}
// Build a query with a rooted $or.
- auto queryRequest = std::make_unique<QueryRequest>(nss);
- queryRequest->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(BSON("$or" << BSON_ARRAY(BSON("p1" << 1) << BSON("p2" << 2))));
auto canonicalQuery =
- uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(queryRequest)));
+ uassertStatusOK(CanonicalQuery::canonicalize(opCtx(), std::move(findCommand)));
boost::optional<AutoGetCollectionForReadCommand> collLock;
collLock.emplace(opCtx(), nss);
diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp
index c55d7bd17f1..4ef593dfa76 100644
--- a/src/mongo/dbtests/query_stage_update.cpp
+++ b/src/mongo/dbtests/query_stage_update.cpp
@@ -99,9 +99,9 @@ public:
}
unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
- auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(qr));
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
+ auto statusWithCQ = CanonicalQuery::canonicalize(&_opCtx, std::move(findCommand));
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/executor/remote_command_request.cpp b/src/mongo/executor/remote_command_request.cpp
index 8eb623cde61..fc2af299615 100644
--- a/src/mongo/executor/remote_command_request.cpp
+++ b/src/mongo/executor/remote_command_request.cpp
@@ -36,7 +36,7 @@
#include "mongo/bson/simple_bsonobj_comparator.h"
#include "mongo/db/api_parameters.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/str.h"
@@ -79,8 +79,8 @@ RemoteCommandRequestBase::RemoteCommandRequestBase(RequestId requestId,
// the OpCtx. It should never be specified explicitly.
uassert(4924403,
str::stream() << "Command request object should not manually specify "
- << QueryRequest::kMaxTimeMSOpOnlyField,
- !cmdObj.hasField(QueryRequest::kMaxTimeMSOpOnlyField));
+ << query_request_helper::kMaxTimeMSOpOnlyField,
+ !cmdObj.hasField(query_request_helper::kMaxTimeMSOpOnlyField));
if (hedgeOptions) {
operationKey.emplace(UUID::gen());
diff --git a/src/mongo/s/balancer_configuration_test.cpp b/src/mongo/s/balancer_configuration_test.cpp
index 3d4af2a4fbb..546b7f67d4f 100644
--- a/src/mongo/s/balancer_configuration_test.cpp
+++ b/src/mongo/s/balancer_configuration_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/bsonmisc.h"
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/executor/remote_command_request.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
#include "mongo/rpc/metadata/tracking_metadata.h"
@@ -80,10 +80,10 @@ protected:
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto findCommand = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss().ns(), "config.settings");
- ASSERT_BSONOBJ_EQ(query->getFilter(), BSON("_id" << key));
+ ASSERT_EQ(findCommand->getNamespaceOrUUID().nss()->ns(), "config.settings");
+ ASSERT_BSONOBJ_EQ(findCommand->getFilter(), BSON("_id" << key));
checkReadConcern(request.cmdObj, Timestamp(0, 0), repl::OpTime::kUninitializedTerm);
diff --git a/src/mongo/s/catalog/sharding_catalog_client_test.cpp b/src/mongo/s/catalog/sharding_catalog_client_test.cpp
index 8a4aa9e2ad4..676db551c23 100644
--- a/src/mongo/s/catalog/sharding_catalog_client_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_client_test.cpp
@@ -37,7 +37,7 @@
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/commands.h"
#include "mongo/db/ops/write_ops.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/time_proof_service.h"
#include "mongo/executor/task_executor.h"
@@ -101,10 +101,11 @@ TEST_F(ShardingCatalogClientTest, GetCollectionExisting) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
// Ensure the query is correct
- ASSERT_EQ(query->nss(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ CollectionType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(),
BSON(CollectionType::kNssFieldName << expectedColl.getNss().ns()));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -171,9 +172,10 @@ TEST_F(ShardingCatalogClientTest, GetDatabaseExisting) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), DatabaseType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ DatabaseType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSON(DatabaseType::name(expectedDb.getName())));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT(!query->getLimit());
@@ -300,9 +302,10 @@ TEST_F(ShardingCatalogClientTest, GetAllShardsValid) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), ShardType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ ShardType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -397,9 +400,10 @@ TEST_F(ShardingCatalogClientTest, GetChunksForNSWithSortAndLimit) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), ChunkType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ ChunkType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), chunksQuery);
ASSERT_BSONOBJ_EQ(query->getSort(), BSON(ChunkType::lastmod() << -1));
ASSERT_EQ(query->getLimit().get(), 1);
@@ -454,9 +458,10 @@ TEST_F(ShardingCatalogClientTest, GetChunksForNSNoSortNoLimit) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), ChunkType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ ChunkType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), chunksQuery);
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -766,9 +771,10 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsValidResultsNoDb) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ CollectionType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -813,9 +819,10 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsValidResultsWithDb) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ CollectionType::ConfigNS);
{
BSONObjBuilder b;
b.appendRegex(CollectionType::kNssFieldName, "^test\\.");
@@ -850,9 +857,10 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsInvalidCollectionType) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ CollectionType::ConfigNS);
{
BSONObjBuilder b;
b.appendRegex(CollectionType::kNssFieldName, "^test\\.");
@@ -886,9 +894,10 @@ TEST_F(ShardingCatalogClientTest, GetDatabasesForShardValid) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), DatabaseType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ DatabaseType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(),
BSON(DatabaseType::primary(dbt1.getPrimary().toString())));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -954,9 +963,10 @@ TEST_F(ShardingCatalogClientTest, GetTagsForCollection) {
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss(), TagsType::ConfigNS);
+ ASSERT_EQ(query->getNamespaceOrUUID().nss().value_or(NamespaceString()),
+ TagsType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSON(TagsType::ns("TestDB.TestColl")));
ASSERT_BSONOBJ_EQ(query->getSort(), BSON(TagsType::min() << 1));
@@ -1301,14 +1311,15 @@ TEST_F(ShardingCatalogClientTest, GetNewKeys) {
ASSERT_EQ("admin", request.dbname);
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
BSONObj expectedQuery(
fromjson("{purpose: 'none',"
"expiresAt: {$gt: {$timestamp: {t: 1234, i: 5678}}}}"));
- ASSERT_EQ(NamespaceString::kKeysCollectionNamespace, query->nss());
+ ASSERT_EQ(NamespaceString::kKeysCollectionNamespace,
+ query->getNamespaceOrUUID().nss().value_or(NamespaceString()));
ASSERT_BSONOBJ_EQ(expectedQuery, query->getFilter());
ASSERT_BSONOBJ_EQ(BSON("expiresAt" << 1), query->getSort());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -1353,13 +1364,14 @@ TEST_F(ShardingCatalogClientTest, GetNewKeysWithEmptyCollection) {
ASSERT_EQ("admin", request.dbname);
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
BSONObj expectedQuery(
fromjson("{purpose: 'none',"
"expiresAt: {$gt: {$timestamp: {t: 1234, i: 5678}}}}"));
- ASSERT_EQ(NamespaceString::kKeysCollectionNamespace, query->nss());
+ ASSERT_EQ(NamespaceString::kKeysCollectionNamespace,
+ query->getNamespaceOrUUID().nss().value_or(NamespaceString()));
ASSERT_BSONOBJ_EQ(expectedQuery, query->getFilter());
ASSERT_BSONOBJ_EQ(BSON("expiresAt" << 1), query->getSort());
ASSERT_FALSE(query->getLimit().is_initialized());
diff --git a/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp b/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
index 849d094032e..a1cb36b7c4b 100644
--- a/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_write_retry_test.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/ops/write_ops.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/storage/duplicate_key_error_info.h"
#include "mongo/db/write_concern.h"
#include "mongo/executor/task_executor.h"
@@ -149,7 +149,7 @@ TEST_F(InsertRetryTest, RetryOnNetworkErrorFails) {
void assertFindRequestHasFilter(const RemoteCommandRequest& request, BSONObj filter) {
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj).body;
- auto query = QueryRequest::makeFromFindCommandForTests(cmd, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(cmd);
ASSERT_BSONOBJ_EQ(filter, query->getFilter());
}
diff --git a/src/mongo/s/catalog_cache_refresh_test.cpp b/src/mongo/s/catalog_cache_refresh_test.cpp
index b259aa94929..eafa39348ae 100644
--- a/src/mongo/s/catalog_cache_refresh_test.cpp
+++ b/src/mongo/s/catalog_cache_refresh_test.cpp
@@ -32,7 +32,7 @@
#include "mongo/platform/basic.h"
#include "mongo/db/concurrency/locker_noop.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/catalog/type_collection.h"
#include "mongo/s/catalog/type_database.h"
@@ -610,7 +610,7 @@ TEST_F(CatalogCacheRefreshTest, ChunkEpochChangeDuringIncrementalLoadRecoveryAft
expectGetCollection(oldVersion.epoch(), shardKeyPattern);
onFindCommand([&](const RemoteCommandRequest& request) {
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto diffQuery = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto diffQuery = query_request_helper::makeFromFindCommandForTests(opMsg.body);
ASSERT_BSONOBJ_EQ(BSON("ns" << kNss.ns() << "lastmod"
<< BSON("$gte" << Timestamp(oldVersion.majorVersion(),
oldVersion.minorVersion()))),
@@ -642,7 +642,7 @@ TEST_F(CatalogCacheRefreshTest, ChunkEpochChangeDuringIncrementalLoadRecoveryAft
// Ensure it is a differential query but starting from version zero (to fetch all the
// chunks) since the incremental refresh above produced a different version
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto diffQuery = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto diffQuery = query_request_helper::makeFromFindCommandForTests(opMsg.body);
ASSERT_BSONOBJ_EQ(BSON("ns" << kNss.ns() << "lastmod" << BSON("$gte" << Timestamp(0, 0))),
diffQuery->getFilter());
@@ -696,7 +696,7 @@ TEST_F(CatalogCacheRefreshTest, IncrementalLoadAfterCollectionEpochChange) {
onFindCommand([&](const RemoteCommandRequest& request) {
// Ensure it is a differential query but starting from version zero
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto diffQuery = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto diffQuery = query_request_helper::makeFromFindCommandForTests(opMsg.body);
ASSERT_BSONOBJ_EQ(BSON("ns" << kNss.ns() << "lastmod" << BSON("$gte" << Timestamp(0, 0))),
diffQuery->getFilter());
@@ -742,7 +742,7 @@ TEST_F(CatalogCacheRefreshTest, IncrementalLoadAfterSplit) {
onFindCommand([&](const RemoteCommandRequest& request) {
// Ensure it is a differential query
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto diffQuery = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto diffQuery = query_request_helper::makeFromFindCommandForTests(opMsg.body);
ASSERT_BSONOBJ_EQ(
BSON("ns" << kNss.ns() << "lastmod"
<< BSON("$gte" << Timestamp(version.majorVersion(), version.minorVersion()))),
diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp
index 4eca62e5395..1ddbccfe938 100644
--- a/src/mongo/s/chunk_manager.cpp
+++ b/src/mongo/s/chunk_manager.cpp
@@ -384,23 +384,24 @@ void ChunkManager::getShardIdsForQuery(boost::intrusive_ptr<ExpressionContext> e
const BSONObj& query,
const BSONObj& collation,
std::set<ShardId>* shardIds) const {
- auto qr = std::make_unique<QueryRequest>(_rt->optRt->nss());
- qr->setFilter(query);
+ auto findCommand = std::make_unique<FindCommand>(_rt->optRt->nss());
+ findCommand->setFilter(query.getOwned());
if (auto uuid = getUUID())
expCtx->uuid = uuid;
if (!collation.isEmpty()) {
- qr->setCollation(collation);
+ findCommand->setCollation(collation.getOwned());
} else if (_rt->optRt->getDefaultCollator()) {
auto defaultCollator = _rt->optRt->getDefaultCollator();
- qr->setCollation(defaultCollator->getSpec().toBSON());
+ findCommand->setCollation(defaultCollator->getSpec().toBSON());
expCtx->setCollator(defaultCollator->clone());
}
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(expCtx->opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures));
diff --git a/src/mongo/s/chunk_manager_index_bounds_test.cpp b/src/mongo/s/chunk_manager_index_bounds_test.cpp
index 8b8c490fd92..611c50fe13f 100644
--- a/src/mongo/s/chunk_manager_index_bounds_test.cpp
+++ b/src/mongo/s/chunk_manager_index_bounds_test.cpp
@@ -56,13 +56,14 @@ protected:
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
BSONObj queryObj = fromjson(queryStr);
const NamespaceString nss("test.foo");
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(queryObj);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(queryObj);
boost::intrusive_ptr<ExpressionContextForTest> expCtx(
new ExpressionContextForTest(operationContext()));
auto statusWithCQ =
CanonicalQuery::canonicalize(operationContext(),
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/s/client/shard_remote.cpp b/src/mongo/s/client/shard_remote.cpp
index a9d12cf30b3..77250817f40 100644
--- a/src/mongo/s/client/shard_remote.cpp
+++ b/src/mongo/s/client/shard_remote.cpp
@@ -44,7 +44,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/logical_time.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/executor/task_executor_pool.h"
#include "mongo/logv2/log.h"
@@ -79,13 +79,13 @@ BSONObj appendMaxTimeToCmdObj(Milliseconds maxTimeMSOverride, const BSONObj& cmd
// Remove the user provided maxTimeMS so we can attach the one from the override
for (const auto& elem : cmdObj) {
- if (elem.fieldNameStringData() != QueryRequest::cmdOptionMaxTimeMS) {
+ if (elem.fieldNameStringData() != query_request_helper::cmdOptionMaxTimeMS) {
updatedCmdBuilder.append(elem);
}
}
if (maxTimeMSOverride < Milliseconds::max()) {
- updatedCmdBuilder.append(QueryRequest::cmdOptionMaxTimeMS,
+ updatedCmdBuilder.append(query_request_helper::cmdOptionMaxTimeMS,
durationCount<Milliseconds>(maxTimeMSOverride));
}
@@ -376,20 +376,21 @@ StatusWith<Shard::QueryResponse> ShardRemote::_exhaustiveFindOnConfig(
BSONObjBuilder findCmdBuilder;
{
- QueryRequest qr(nss);
- qr.setFilter(query);
- qr.setSort(sort);
- qr.setReadConcern(readConcernObj);
- qr.setLimit(limit ? static_cast<boost::optional<std::int64_t>>(*limit) : boost::none);
+ FindCommand findCommand(nss);
+ findCommand.setFilter(query.getOwned());
+ findCommand.setSort(sort.getOwned());
+ findCommand.setReadConcern(readConcernObj.getOwned());
+ findCommand.setLimit(limit ? static_cast<boost::optional<std::int64_t>>(*limit)
+ : boost::none);
if (hint) {
- qr.setHint(*hint);
+ findCommand.setHint(*hint);
}
if (maxTimeMS < Milliseconds::max()) {
- qr.setMaxTimeMS(durationCount<Milliseconds>(maxTimeMS));
+ findCommand.setMaxTimeMS(durationCount<Milliseconds>(maxTimeMS));
}
- qr.asFindCommand(&findCmdBuilder);
+ findCommand.serialize(BSONObj(), &findCmdBuilder);
}
return _runExhaustiveCursorCommand(opCtx,
diff --git a/src/mongo/s/cluster_identity_loader_test.cpp b/src/mongo/s/cluster_identity_loader_test.cpp
index bf35b79990d..b9f7ba1f029 100644
--- a/src/mongo/s/cluster_identity_loader_test.cpp
+++ b/src/mongo/s/cluster_identity_loader_test.cpp
@@ -35,7 +35,7 @@
#include "mongo/client/remote_command_targeter_mock.h"
#include "mongo/db/commands.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/service_context.h"
#include "mongo/executor/task_executor.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
@@ -77,9 +77,9 @@ public:
rpc::TrackingMetadata::removeTrackingData(request.metadata));
auto opMsg = OpMsgRequest::fromDBAndBody(request.dbname, request.cmdObj);
- auto query = QueryRequest::makeFromFindCommandForTests(opMsg.body, false);
+ auto query = query_request_helper::makeFromFindCommandForTests(opMsg.body);
- ASSERT_EQ(query->nss().ns(), "config.version");
+ ASSERT_EQ(query->getNamespaceOrUUID().nss()->ns(), "config.version");
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp
index 0403314e50b..20508a7fc66 100644
--- a/src/mongo/s/commands/cluster_find_cmd.cpp
+++ b/src/mongo/s/commands/cluster_find_cmd.cpp
@@ -56,31 +56,29 @@ using std::vector;
const char kTermField[] = "term";
-// Parses the command object to a QueryRequest, validates that no runtime constants were supplied
+// Parses the command object to a FindCommand, validates that no runtime constants were supplied
// with the command, and sets the constant runtime values that will be forwarded to each shard.
-std::unique_ptr<QueryRequest> parseCmdObjectToQueryRequest(OperationContext* opCtx,
- NamespaceString nss,
- BSONObj cmdObj,
- bool isExplain) {
- auto qr =
- QueryRequest::makeFromFindCommand(std::move(cmdObj),
- isExplain,
- std::move(nss),
- APIParameters::get(opCtx).getAPIStrict().value_or(false));
- if (!qr->getReadConcern()) {
+std::unique_ptr<FindCommand> parseCmdObjectToFindCommand(OperationContext* opCtx,
+ NamespaceString nss,
+ BSONObj cmdObj) {
+ auto findCommand = query_request_helper::makeFromFindCommand(
+ std::move(cmdObj),
+ std::move(nss),
+ APIParameters::get(opCtx).getAPIStrict().value_or(false));
+ if (!findCommand->getReadConcern()) {
if (opCtx->isStartingMultiDocumentTransaction() || !opCtx->inMultiDocumentTransaction()) {
// If there is no explicit readConcern in the cmdObj, and this is either the first
// operation in a transaction, or not running in a transaction, then use the readConcern
// from the opCtx (which may be a cluster-wide default).
const auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx);
- qr->setReadConcern(readConcernArgs.toBSONInner());
+ findCommand->setReadConcern(readConcernArgs.toBSONInner());
}
}
uassert(51202,
"Cannot specify runtime constants option to a mongos",
- !qr->getLegacyRuntimeConstants());
- qr->setLegacyRuntimeConstants(Variables::generateRuntimeConstants(opCtx));
- return qr;
+ !findCommand->getLegacyRuntimeConstants());
+ findCommand->setLegacyRuntimeConstants(Variables::generateRuntimeConstants(opCtx));
+ return findCommand;
}
/**
@@ -153,31 +151,31 @@ public:
void explain(OperationContext* opCtx,
ExplainOptions::Verbosity verbosity,
rpc::ReplyBuilderInterface* result) override {
- // Parse the command BSON to a QueryRequest.
- const bool isExplain = true;
- auto qr = parseCmdObjectToQueryRequest(opCtx, ns(), _request.body, isExplain);
+ // Parse the command BSON to a FindCommand.
+ auto findCommand = parseCmdObjectToFindCommand(opCtx, ns(), _request.body);
try {
const auto explainCmd =
- ClusterExplain::wrapAsExplain(qr->asFindCommand(), verbosity);
+ ClusterExplain::wrapAsExplain(findCommand->toBSON(BSONObj()), verbosity);
long long millisElapsed;
std::vector<AsyncRequestsSender::Response> shardResponses;
// We will time how long it takes to run the commands on the shards.
Timer timer;
- const auto routingInfo = uassertStatusOK(
- Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, qr->nss()));
- shardResponses =
- scatterGatherVersionedTargetByRoutingTable(opCtx,
- qr->nss().db(),
- qr->nss(),
- routingInfo,
- explainCmd,
- ReadPreferenceSetting::get(opCtx),
- Shard::RetryPolicy::kIdempotent,
- qr->getFilter(),
- qr->getCollation());
+ const auto routingInfo =
+ uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(
+ opCtx, *findCommand->getNamespaceOrUUID().nss()));
+ shardResponses = scatterGatherVersionedTargetByRoutingTable(
+ opCtx,
+ findCommand->getNamespaceOrUUID().nss()->db(),
+ *findCommand->getNamespaceOrUUID().nss(),
+ routingInfo,
+ explainCmd,
+ ReadPreferenceSetting::get(opCtx),
+ Shard::RetryPolicy::kIdempotent,
+ findCommand->getFilter(),
+ findCommand->getCollation());
millisElapsed = timer.millis();
const char* mongosStageName =
@@ -195,7 +193,8 @@ public:
auto bodyBuilder = result->getBodyBuilder();
bodyBuilder.resetToEmpty();
- auto aggCmdOnView = uassertStatusOK(qr->asAggregationCommand());
+ auto aggCmdOnView =
+ uassertStatusOK(query_request_helper::asAggregationCommand(*findCommand));
auto viewAggregationCommand =
OpMsgRequest::fromDBAndBody(_dbName, aggCmdOnView).body;
@@ -226,13 +225,13 @@ public:
opCtx, mongo::LogicalOp::opQuery);
});
- const bool isExplain = false;
- auto qr = parseCmdObjectToQueryRequest(opCtx, ns(), _request.body, isExplain);
+ auto findCommand = parseCmdObjectToFindCommand(opCtx, ns(), _request.body);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures));
@@ -261,7 +260,8 @@ public:
} catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) {
result->reset();
- auto aggCmdOnView = uassertStatusOK(cq->getQueryRequest().asAggregationCommand());
+ auto aggCmdOnView = uassertStatusOK(
+ query_request_helper::asAggregationCommand(cq->getFindCommand()));
auto viewAggregationCommand =
OpMsgRequest::fromDBAndBody(_dbName, aggCmdOnView).body;
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index bb97a416c7d..f4db2effe4b 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -58,7 +58,7 @@
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/query/find_common.h"
#include "mongo/db/query/getmore_request.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/read_write_concern_defaults.h"
#include "mongo/db/stats/api_version_metrics.h"
#include "mongo/db/stats/counters.h"
@@ -498,9 +498,9 @@ void ParseAndRunCommand::_parseCommand() {
// maxTimeMS altogether on a getMore command.
uassert(ErrorCodes::InvalidOptions,
"no such command option $maxTimeMs; use maxTimeMS instead",
- request.body[QueryRequest::queryOptionMaxTimeMS].eoo());
+ request.body[query_request_helper::queryOptionMaxTimeMS].eoo());
const int maxTimeMS =
- uassertStatusOK(parseMaxTimeMS(request.body[QueryRequest::cmdOptionMaxTimeMS]));
+ uassertStatusOK(parseMaxTimeMS(request.body[query_request_helper::cmdOptionMaxTimeMS]));
if (maxTimeMS > 0 && command->getLogicalOp() != LogicalOp::opGetMore) {
opCtx->setDeadlineAfterNowBy(Milliseconds{maxTimeMS}, ErrorCodes::MaxTimeMSExpired);
}
@@ -1096,29 +1096,29 @@ DbResponse Strategy::queryOp(OperationContext* opCtx, const NamespaceString& nss
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures));
- const QueryRequest& queryRequest = canonicalQuery->getQueryRequest();
+ const FindCommand& findCommand = canonicalQuery->getFindCommand();
// Handle query option $maxTimeMS (not used with commands).
- if (queryRequest.getMaxTimeMS() > 0) {
+ if (findCommand.getMaxTimeMS().value_or(0) > 0) {
uassert(50749,
"Illegal attempt to set operation deadline within DBDirectClient",
!opCtx->getClient()->isInDirectClient());
- opCtx->setDeadlineAfterNowBy(Milliseconds{queryRequest.getMaxTimeMS()},
+ opCtx->setDeadlineAfterNowBy(Milliseconds{findCommand.getMaxTimeMS().value_or(0)},
ErrorCodes::MaxTimeMSExpired);
}
opCtx->checkForInterrupt(); // May trigger maxTimeAlwaysTimeOut fail point.
// If the $explain flag was set, we must run the operation on the shards as an explain command
// rather than a find command.
- if (queryRequest.isExplain()) {
- const BSONObj findCommand = queryRequest.asFindCommand();
+ if (canonicalQuery->getExplain()) {
+ const BSONObj findCommandObj = findCommand.toBSON(BSONObj());
// We default to allPlansExecution verbosity.
const auto verbosity = ExplainOptions::Verbosity::kExecAllPlans;
BSONObjBuilder explainBuilder;
Strategy::explainFind(opCtx,
+ findCommandObj,
findCommand,
- queryRequest,
verbosity,
ReadPreferenceSetting::get(opCtx),
&explainBuilder);
@@ -1444,12 +1444,12 @@ void Strategy::writeOp(std::shared_ptr<RequestExecutionContext> rec) {
}
void Strategy::explainFind(OperationContext* opCtx,
- const BSONObj& findCommand,
- const QueryRequest& qr,
+ const BSONObj& findCommandObj,
+ const FindCommand& findCommand,
ExplainOptions::Verbosity verbosity,
const ReadPreferenceSetting& readPref,
BSONObjBuilder* out) {
- const auto explainCmd = ClusterExplain::wrapAsExplain(findCommand, verbosity);
+ const auto explainCmd = ClusterExplain::wrapAsExplain(findCommandObj, verbosity);
long long millisElapsed;
std::vector<AsyncRequestsSender::Response> shardResponses;
@@ -1460,18 +1460,20 @@ void Strategy::explainFind(OperationContext* opCtx,
// We will time how long it takes to run the commands on the shards.
Timer timer;
try {
- const auto routingInfo = uassertStatusOK(
- Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, qr.nss()));
- shardResponses =
- scatterGatherVersionedTargetByRoutingTable(opCtx,
- qr.nss().db(),
- qr.nss(),
- routingInfo,
- explainCmd,
- readPref,
- Shard::RetryPolicy::kIdempotent,
- qr.getFilter(),
- qr.getCollation());
+ invariant(findCommand.getNamespaceOrUUID().nss());
+ const auto routingInfo =
+ uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(
+ opCtx, *findCommand.getNamespaceOrUUID().nss()));
+ shardResponses = scatterGatherVersionedTargetByRoutingTable(
+ opCtx,
+ findCommand.getNamespaceOrUUID().nss()->db(),
+ *findCommand.getNamespaceOrUUID().nss(),
+ routingInfo,
+ explainCmd,
+ readPref,
+ Shard::RetryPolicy::kIdempotent,
+ findCommand.getFilter(),
+ findCommand.getCollation());
millisElapsed = timer.millis();
break;
} catch (ExceptionFor<ErrorCodes::ShardInvalidatedForTargeting>&) {
@@ -1524,9 +1526,9 @@ void Strategy::explainFind(OperationContext* opCtx,
}
const char* mongosStageName =
- ClusterExplain::getStageNameForReadOp(shardResponses.size(), findCommand);
+ ClusterExplain::getStageNameForReadOp(shardResponses.size(), findCommandObj);
uassertStatusOK(ClusterExplain::buildExplainResult(
- opCtx, shardResponses, mongosStageName, millisElapsed, findCommand, out));
+ opCtx, shardResponses, mongosStageName, millisElapsed, findCommandObj, out));
}
} // namespace mongo
diff --git a/src/mongo/s/commands/strategy.h b/src/mongo/s/commands/strategy.h
index 95f3f8c9449..4ea30690bf2 100644
--- a/src/mongo/s/commands/strategy.h
+++ b/src/mongo/s/commands/strategy.h
@@ -43,7 +43,7 @@ struct DbResponse;
class Message;
class NamespaceString;
class OperationContext;
-class QueryRequest;
+class FindCommand;
/**
* Legacy interface for processing client read/write/cmd requests.
@@ -93,8 +93,8 @@ public:
* $explain modifier.
*/
static void explainFind(OperationContext* opCtx,
- const BSONObj& findCommand,
- const QueryRequest& qr,
+ const BSONObj& findCommandObj,
+ const FindCommand& findCommand,
ExplainOptions::Verbosity verbosity,
const ReadPreferenceSetting& readPref,
BSONObjBuilder* out);
diff --git a/src/mongo/s/query/async_results_merger_test.cpp b/src/mongo/s/query/async_results_merger_test.cpp
index 00112add13b..fd156343e2a 100644
--- a/src/mongo/s/query/async_results_merger_test.cpp
+++ b/src/mongo/s/query/async_results_merger_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/db/pipeline/resume_token.h"
#include "mongo/db/query/cursor_response.h"
#include "mongo/db/query/getmore_request.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/executor/task_executor.h"
#include "mongo/s/catalog/type_shard.h"
#include "mongo/s/client/shard_registry.h"
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp
index 7fac4105e93..02c4b570ac9 100644
--- a/src/mongo/s/query/cluster_find.cpp
+++ b/src/mongo/s/query/cluster_find.cpp
@@ -84,86 +84,94 @@ static const int kPerDocumentOverheadBytesUpperBound = 10;
const char kFindCmdName[] = "find";
/**
- * Given the QueryRequest 'qr' being executed by mongos, returns a copy of the query which is
- * suitable for forwarding to the targeted hosts.
+ * Given the FindCommand 'findCommand' being executed by mongos, returns a copy of the query which
+ * is suitable for forwarding to the targeted hosts.
*/
-StatusWith<std::unique_ptr<QueryRequest>> transformQueryForShards(
- const QueryRequest& qr, bool appendGeoNearDistanceProjection) {
+StatusWith<std::unique_ptr<FindCommand>> transformQueryForShards(
+ const FindCommand& findCommand, bool appendGeoNearDistanceProjection) {
// If there is a limit, we forward the sum of the limit and the skip.
boost::optional<int64_t> newLimit;
- if (qr.getLimit()) {
+ if (findCommand.getLimit()) {
long long newLimitValue;
- if (overflow::add(*qr.getLimit(), qr.getSkip().value_or(0), &newLimitValue)) {
+ if (overflow::add(
+ *findCommand.getLimit(), findCommand.getSkip().value_or(0), &newLimitValue)) {
return Status(
ErrorCodes::Overflow,
str::stream()
<< "sum of limit and skip cannot be represented as a 64-bit integer, limit: "
- << *qr.getLimit() << ", skip: " << qr.getSkip().value_or(0));
+ << *findCommand.getLimit() << ", skip: " << findCommand.getSkip().value_or(0));
}
newLimit = newLimitValue;
}
// Similarly, if nToReturn is set, we forward the sum of nToReturn and the skip.
boost::optional<int64_t> newNToReturn;
- if (qr.getNToReturn()) {
+ if (findCommand.getNtoreturn()) {
// 'singleBatch' and ntoreturn mean the same as 'singleBatch' and limit, so perform the
// conversion.
- if (qr.isSingleBatch()) {
+ if (findCommand.getSingleBatch()) {
int64_t newLimitValue;
- if (overflow::add(*qr.getNToReturn(), qr.getSkip().value_or(0), &newLimitValue)) {
+ if (overflow::add(*findCommand.getNtoreturn(),
+ findCommand.getSkip().value_or(0),
+ &newLimitValue)) {
return Status(ErrorCodes::Overflow,
str::stream()
<< "sum of ntoreturn and skip cannot be represented as a 64-bit "
"integer, ntoreturn: "
- << *qr.getNToReturn() << ", skip: " << qr.getSkip().value_or(0));
+ << *findCommand.getNtoreturn()
+ << ", skip: " << findCommand.getSkip().value_or(0));
}
newLimit = newLimitValue;
} else {
int64_t newNToReturnValue;
- if (overflow::add(*qr.getNToReturn(), qr.getSkip().value_or(0), &newNToReturnValue)) {
+ if (overflow::add(*findCommand.getNtoreturn(),
+ findCommand.getSkip().value_or(0),
+ &newNToReturnValue)) {
return Status(ErrorCodes::Overflow,
str::stream()
<< "sum of ntoreturn and skip cannot be represented as a 64-bit "
"integer, ntoreturn: "
- << *qr.getNToReturn() << ", skip: " << qr.getSkip().value_or(0));
+ << *findCommand.getNtoreturn()
+ << ", skip: " << findCommand.getSkip().value_or(0));
}
newNToReturn = newNToReturnValue;
}
}
// If there is a sort other than $natural, we send a sortKey meta-projection to the remote node.
- BSONObj newProjection = qr.getProj();
- if (!qr.getSort().isEmpty() && !qr.getSort()[QueryRequest::kNaturalSortField]) {
+ BSONObj newProjection = findCommand.getProjection();
+ if (!findCommand.getSort().isEmpty() &&
+ !findCommand.getSort()[query_request_helper::kNaturalSortField]) {
BSONObjBuilder projectionBuilder;
- projectionBuilder.appendElements(qr.getProj());
+ projectionBuilder.appendElements(findCommand.getProjection());
projectionBuilder.append(AsyncResultsMerger::kSortKeyField, kSortKeyMetaProjection);
newProjection = projectionBuilder.obj();
}
if (appendGeoNearDistanceProjection) {
- invariant(qr.getSort().isEmpty());
+ invariant(findCommand.getSort().isEmpty());
BSONObjBuilder projectionBuilder;
- projectionBuilder.appendElements(qr.getProj());
+ projectionBuilder.appendElements(findCommand.getProjection());
projectionBuilder.append(AsyncResultsMerger::kSortKeyField, kGeoNearDistanceMetaProjection);
newProjection = projectionBuilder.obj();
}
- auto newQR = std::make_unique<QueryRequest>(qr);
- newQR->setProj(newProjection);
+ auto newQR = std::make_unique<FindCommand>(findCommand);
+ newQR->setProjection(newProjection);
newQR->setSkip(boost::none);
newQR->setLimit(newLimit);
- newQR->setNToReturn(newNToReturn);
+ newQR->setNtoreturn(newNToReturn);
// Even if the client sends us singleBatch=true, we may need to retrieve
// multiple batches from a shard in order to return the single requested batch to the client.
// Therefore, we must always send singleBatch=false to the shards.
- newQR->setSingleBatchField(false);
+ newQR->setSingleBatch(false);
// Any expansion of the 'showRecordId' flag should have already happened on mongos.
- if (newQR->showRecordId())
+ if (newQR->getShowRecordId())
newQR->setShowRecordId(false);
- invariant(newQR->validate());
+ uassertStatusOK(query_request_helper::validateFindCommand(*newQR));
return std::move(newQR);
}
@@ -178,20 +186,20 @@ std::vector<std::pair<ShardId, BSONObj>> constructRequestsForShards(
const CanonicalQuery& query,
bool appendGeoNearDistanceProjection) {
- std::unique_ptr<QueryRequest> qrToForward;
+ std::unique_ptr<FindCommand> findCommandToForward;
if (shardIds.size() > 1) {
- qrToForward = uassertStatusOK(
- transformQueryForShards(query.getQueryRequest(), appendGeoNearDistanceProjection));
+ findCommandToForward = uassertStatusOK(
+ transformQueryForShards(query.getFindCommand(), appendGeoNearDistanceProjection));
} else {
- // Forwards the QueryRequest as is to a single shard so that limit and skip can
+ // Forwards the FindCommand as is to a single shard so that limit and skip can
// be applied on mongod.
- qrToForward = std::make_unique<QueryRequest>(query.getQueryRequest());
+ findCommandToForward = std::make_unique<FindCommand>(query.getFindCommand());
}
auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx);
if (readConcernArgs.wasAtClusterTimeSelected()) {
// If mongos selected atClusterTime or received it from client, transmit it to shard.
- qrToForward->setReadConcern(readConcernArgs.toBSONInner());
+ findCommandToForward->setReadConcern(readConcernArgs.toBSONInner());
}
auto shardRegistry = Grid::get(opCtx)->shardRegistry();
@@ -201,7 +209,7 @@ std::vector<std::pair<ShardId, BSONObj>> constructRequestsForShards(
invariant(!shard->isConfig() || shard->getConnString());
BSONObjBuilder cmdBuilder;
- qrToForward->asFindCommand(&cmdBuilder);
+ findCommandToForward->serialize(BSONObj(), &cmdBuilder);
if (cm.isSharded()) {
cm.getVersion(shardId).appendToCommand(&cmdBuilder);
@@ -240,20 +248,20 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
const ChunkManager& cm,
std::vector<BSONObj>* results,
bool* partialResultsReturned) {
+ auto findCommand = query.getFindCommand();
// Get the set of shards on which we will run the query.
- auto shardIds = getTargetedShardsForQuery(query.getExpCtx(),
- cm,
- query.getQueryRequest().getFilter(),
- query.getQueryRequest().getCollation());
+ auto shardIds = getTargetedShardsForQuery(
+ query.getExpCtx(), cm, findCommand.getFilter(), findCommand.getCollation());
// Construct the query and parameters. Defer setting skip and limit here until
// we determine if the query is targeting multi-shards or a single shard below.
ClusterClientCursorParams params(
query.nss(), APIParameters::get(opCtx), readPref, ReadConcernArgs::get(opCtx));
params.originatingCommandObj = CurOp::get(opCtx)->opDescription().getOwned();
- params.batchSize = query.getQueryRequest().getEffectiveBatchSize();
- params.tailableMode = query.getQueryRequest().getTailableMode();
- params.isAllowPartialResults = query.getQueryRequest().isAllowPartialResults();
+ params.batchSize =
+ findCommand.getBatchSize() ? findCommand.getBatchSize() : findCommand.getNtoreturn();
+ params.tailableMode = query_request_helper::getTailableMode(findCommand);
+ params.isAllowPartialResults = findCommand.getAllowPartialResults();
params.lsid = opCtx->getLogicalSessionId();
params.txnNumber = opCtx->getTxnNumber();
params.originatingPrivileges = {
@@ -274,8 +282,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// sort on mongos. Including a $natural anywhere in the sort spec results in the whole sort
// being considered a hint to use a collection scan.
BSONObj sortComparatorObj;
- if (query.getSortPattern() &&
- !query.getQueryRequest().getSort()[QueryRequest::kNaturalSortField]) {
+ if (query.getSortPattern() && !findCommand.getSort()[query_request_helper::kNaturalSortField]) {
// We have already validated the input sort object. Serialize the raw sort spec into one
// suitable for use as the ordering specification in BSONObj::woCompare(). In particular, we
// want to eliminate sorts using expressions (like $meta) and replace them with a
@@ -303,7 +310,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// Tailable cursors can't have a sort, which should have already been validated.
tassert(4457013,
"tailable cursor unexpectedly has a sort",
- sortComparatorObj.isEmpty() || !query.getQueryRequest().isTailable());
+ sortComparatorObj.isEmpty() || !findCommand.getTailable());
// Construct the requests that we will use to establish cursors on the targeted shards,
// attaching the shardVersion and txnNumber, if necessary.
@@ -317,7 +324,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
query.nss(),
readPref,
requests,
- query.getQueryRequest().isAllowPartialResults());
+ findCommand.getAllowPartialResults());
// Determine whether the cursor we may eventually register will be single- or multi-target.
@@ -328,9 +335,8 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// Only set skip, limit and sort to be applied to on the router for the multi-shard case. For
// the single-shard case skip/limit as well as sorts are appled on mongod.
if (cursorType == ClusterCursorManager::CursorType::MultiTarget) {
- const auto qr = query.getQueryRequest();
- params.skipToApplyOnRouter = qr.getSkip();
- params.limit = qr.getLimit();
+ params.skipToApplyOnRouter = findCommand.getSkip();
+ params.limit = findCommand.getLimit();
params.sortToApplyOnRouter = sortComparatorObj;
params.compareWholeSortKeyOnRouter = compareWholeSortKeyOnRouter;
}
@@ -350,7 +356,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// This loop will not result in actually calling getMore against shards, but just loading
// results from the initial batches (that were obtained while establishing cursors) into
// 'results'.
- while (!FindCommon::enoughForFirstBatch(query.getQueryRequest(), results->size())) {
+ while (!FindCommon::enoughForFirstBatch(findCommand, results->size())) {
auto next = uassertStatusOK(ccc->next(RouterExecStage::ExecContext::kInitialFind));
if (next.isEOF()) {
@@ -381,7 +387,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
ccc->detachFromOperationContext();
- if (query.getQueryRequest().isSingleBatch() && !ccc->isTailable()) {
+ if (findCommand.getSingleBatch() && !ccc->isTailable()) {
cursorState = ClusterCursorManager::CursorState::Exhausted;
}
@@ -408,7 +414,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// Register the cursor with the cursor manager for subsequent getMore's.
auto cursorManager = Grid::get(opCtx)->getCursorManager();
- const auto cursorLifetime = query.getQueryRequest().isNoCursorTimeout()
+ const auto cursorLifetime = findCommand.getNoCursorTimeout()
? ClusterCursorManager::CursorLifetime::Immortal
: ClusterCursorManager::CursorLifetime::Mortal;
auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames();
@@ -488,19 +494,19 @@ CursorId ClusterFind::runQuery(OperationContext* opCtx,
// We must always have a BSONObj vector into which to output our results.
invariant(results);
+ auto findCommand = query.getFindCommand();
// Projection on the reserved sort key field is illegal in mongos.
- if (query.getQueryRequest().getProj().hasField(AsyncResultsMerger::kSortKeyField)) {
+ if (findCommand.getProjection().hasField(AsyncResultsMerger::kSortKeyField)) {
uasserted(ErrorCodes::BadValue,
str::stream() << "Projection contains illegal field '"
<< AsyncResultsMerger::kSortKeyField
- << "': " << query.getQueryRequest().getProj());
+ << "': " << findCommand.getProjection());
}
// Attempting to establish a resumable query through mongoS is illegal.
uassert(ErrorCodes::BadValue,
"Queries on mongoS may not request or provide a resume token",
- !query.getQueryRequest().getRequestResumeToken() &&
- query.getQueryRequest().getResumeAfter().isEmpty());
+ !findCommand.getRequestResumeToken() && findCommand.getResumeAfter().isEmpty());
auto const catalogCache = Grid::get(opCtx)->catalogCache();
diff --git a/src/mongo/s/query/results_merger_test_fixture.h b/src/mongo/s/query/results_merger_test_fixture.h
index d653bfe0bfa..10978c11cb7 100644
--- a/src/mongo/s/query/results_merger_test_fixture.h
+++ b/src/mongo/s/query/results_merger_test_fixture.h
@@ -72,22 +72,22 @@ protected:
if (findCmd) {
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody(kTestNss.db(), *findCmd).body;
- const auto qr =
- QueryRequest::makeFromFindCommandForTests(cmd, false /* isExplain */, kTestNss);
- if (!qr->getSort().isEmpty()) {
- params.setSort(qr->getSort().getOwned());
+ const auto findCommand =
+ query_request_helper::makeFromFindCommandForTests(cmd, kTestNss);
+ if (!findCommand->getSort().isEmpty()) {
+ params.setSort(findCommand->getSort().getOwned());
}
if (getMoreBatchSize) {
params.setBatchSize(getMoreBatchSize);
} else {
- params.setBatchSize(qr->getBatchSize()
- ? boost::optional<std::int64_t>(
- static_cast<std::int64_t>(*qr->getBatchSize()))
+ params.setBatchSize(findCommand->getBatchSize()
+ ? boost::optional<std::int64_t>(static_cast<std::int64_t>(
+ *findCommand->getBatchSize()))
: boost::none);
}
- params.setTailableMode(qr->getTailableMode());
- params.setAllowPartialResults(qr->isAllowPartialResults());
+ params.setTailableMode(query_request_helper::getTailableMode(*findCommand));
+ params.setAllowPartialResults(findCommand->getAllowPartialResults());
}
OperationSessionInfoFromClient sessionInfo;
diff --git a/src/mongo/s/request_types/set_shard_version_request.cpp b/src/mongo/s/request_types/set_shard_version_request.cpp
index de6d902b6cf..808f480a725 100644
--- a/src/mongo/s/request_types/set_shard_version_request.cpp
+++ b/src/mongo/s/request_types/set_shard_version_request.cpp
@@ -35,7 +35,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/bson/util/bson_extract.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/str.h"
diff --git a/src/mongo/s/sessions_collection_sharded.cpp b/src/mongo/s/sessions_collection_sharded.cpp
index 76946cbd900..c986fabc535 100644
--- a/src/mongo/s/sessions_collection_sharded.cpp
+++ b/src/mongo/s/sessions_collection_sharded.cpp
@@ -34,7 +34,7 @@
#include "mongo/db/matcher/extensions_callback_noop.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/sessions_collection_rs.h"
#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/rpc/op_msg.h"
@@ -172,13 +172,14 @@ LogicalSessionIdSet SessionsCollectionSharded::findRemovedSessions(
toSend =
OpMsgRequest::fromDBAndBody(NamespaceString::kLogicalSessionsNamespace.db(), toSend)
.body;
- auto qr = QueryRequest::makeFromFindCommand(
- toSend, false, NamespaceString::kLogicalSessionsNamespace, apiStrict);
+ auto findCommand = query_request_helper::makeFromFindCommand(
+ toSend, NamespaceString::kLogicalSessionsNamespace, apiStrict);
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false,
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kBanAllSpecialFeatures));
diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp
index 94e6db3dbea..96156876552 100644
--- a/src/mongo/s/shard_key_pattern.cpp
+++ b/src/mongo/s/shard_key_pattern.cpp
@@ -390,13 +390,14 @@ BSONObj ShardKeyPattern::emplaceMissingShardKeyValuesForDocument(const BSONObj d
StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext* opCtx,
const NamespaceString& nss,
const BSONObj& basicQuery) const {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(basicQuery);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(basicQuery.getOwned());
const boost::intrusive_ptr<ExpressionContext> expCtx;
auto statusWithCQ =
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -409,15 +410,16 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext*
StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(
boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& basicQuery) const {
- auto qr = std::make_unique<QueryRequest>(expCtx->ns);
- qr->setFilter(basicQuery);
+ auto findCommand = std::make_unique<FindCommand>(expCtx->ns);
+ findCommand->setFilter(basicQuery.getOwned());
if (!expCtx->getCollatorBSON().isEmpty()) {
- qr->setCollation(expCtx->getCollatorBSON());
+ findCommand->setCollation(expCtx->getCollatorBSON().getOwned());
}
auto statusWithCQ =
CanonicalQuery::canonicalize(expCtx->opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
diff --git a/src/mongo/s/sharding_router_test_fixture.cpp b/src/mongo/s/sharding_router_test_fixture.cpp
index 3e42317a93e..8c7af5b2001 100644
--- a/src/mongo/s/sharding_router_test_fixture.cpp
+++ b/src/mongo/s/sharding_router_test_fixture.cpp
@@ -44,7 +44,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/query/collation/collator_factory_mock.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/vector_clock_metadata_hook.h"
#include "mongo/executor/task_executor_pool.h"
@@ -257,8 +257,8 @@ void ShardingTestFixture::expectGetShards(const std::vector<ShardType>& shards)
// If there is no '$db', append it.
auto cmd = OpMsgRequest::fromDBAndBody(nss.db(), request.cmdObj).body;
- auto query = QueryRequest::makeFromFindCommandForTests(cmd, false, nss);
- ASSERT_EQ(query->nss(), ShardType::ConfigNS);
+ auto query = query_request_helper::makeFromFindCommandForTests(cmd, nss);
+ ASSERT_EQ(*query->getNamespaceOrUUID().nss(), ShardType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
diff --git a/src/mongo/s/write_ops/chunk_manager_targeter.cpp b/src/mongo/s/write_ops/chunk_manager_targeter.cpp
index 7c3b2fb8a27..a6770cc03c7 100644
--- a/src/mongo/s/write_ops/chunk_manager_targeter.cpp
+++ b/src/mongo/s/write_ops/chunk_manager_targeter.cpp
@@ -180,7 +180,7 @@ bool isExactIdQuery(OperationContext* opCtx, const CanonicalQuery& query, const
}
if (CollationIndexKey::isCollatableType(idElt.type()) && cm.isSharded() &&
- !query.getQueryRequest().getCollation().isEmpty() &&
+ !query.getFindCommand().getCollation().isEmpty() &&
!CollatorInterface::collatorsMatch(query.getCollator(), cm.getDefaultCollator())) {
// The collation applies to the _id field, but the user specified a collation which doesn't
@@ -196,13 +196,14 @@ bool isExactIdQuery(OperationContext* opCtx,
const BSONObj query,
const BSONObj collation,
const ChunkManager& cm) {
- auto qr = std::make_unique<QueryRequest>(nss);
- qr->setFilter(query);
+ auto findCommand = std::make_unique<FindCommand>(nss);
+ findCommand->setFilter(query);
if (!collation.isEmpty()) {
- qr->setCollation(collation);
+ findCommand->setCollation(collation);
}
const auto cq = CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
nullptr,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
@@ -506,14 +507,15 @@ std::vector<ShardEndpoint> ChunkManagerTargeter::targetDelete(OperationContext*
// We failed to target a single shard.
// Parse delete query.
- auto qr = std::make_unique<QueryRequest>(_nss);
- qr->setFilter(deleteOp.getQ());
+ auto findCommand = std::make_unique<FindCommand>(_nss);
+ findCommand->setFilter(deleteOp.getQ());
if (!collation.isEmpty()) {
- qr->setCollation(collation);
+ findCommand->setCollation(collation);
}
auto cq = uassertStatusOKWithContext(
CanonicalQuery::canonicalize(opCtx,
- std::move(qr),
+ std::move(findCommand),
+ false, /* isExplain */
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures),
diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp
index 6aaf8a679ad..5585c1483a5 100644
--- a/src/mongo/shell/bench.cpp
+++ b/src/mongo/shell/bench.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/query/cursor_response.h"
#include "mongo/db/query/getmore_request.h"
-#include "mongo/db/query/query_request.h"
+#include "mongo/db/query/query_request_helper.h"
#include "mongo/logv2/log.h"
#include "mongo/scripting/bson_template_evaluator.h"
#include "mongo/stdx/thread.h"
@@ -207,23 +207,24 @@ void abortTransaction(DBClientBase* conn,
}
/**
- * Issues the query 'qr' against 'conn' using read commands. Returns the size of the result set
- * returned by the query.
+ * Issues the query 'findCommand' against 'conn' using read commands. Returns the size of the result
+ * set returned by the query.
*
- * If 'qr' has the 'wantMore' flag set to false and the 'limit' option set to 1LL, then the caller
- * may optionally specify a pointer to an object in 'objOut', which will be filled in with the
- * single object in the query result set (or the empty object, if the result set is empty).
- * If 'qr' doesn't have these options set, then nullptr must be passed for 'objOut'.
+ * If 'findCommand' has the 'wantMore' flag set to false and the 'limit' option set to 1LL, then the
+ * caller may optionally specify a pointer to an object in 'objOut', which will be filled in with
+ * the single object in the query result set (or the empty object, if the result set is empty). If
+ * 'findCommand' doesn't have these options set, then nullptr must be passed for 'objOut'.
*
* On error, throws a AssertionException.
*/
int runQueryWithReadCommands(DBClientBase* conn,
const boost::optional<LogicalSessionIdToClient>& lsid,
boost::optional<TxnNumber> txnNumber,
- std::unique_ptr<QueryRequest> qr,
+ std::unique_ptr<FindCommand> findCommand,
Milliseconds delayBeforeGetMore,
BSONObj* objOut) {
- const auto dbName = qr->nss().db().toString();
+ const auto dbName =
+ findCommand->getNamespaceOrUUID().nss().value_or(NamespaceString()).db().toString();
BSONObj findCommandResult;
uassert(ErrorCodes::CommandFailed,
@@ -231,7 +232,7 @@ int runQueryWithReadCommands(DBClientBase* conn,
runCommandWithSession(
conn,
dbName,
- qr->asFindCommand(),
+ findCommand->toBSON(BSONObj()),
// read command with txnNumber implies performing reads in a
// multi-statement transaction
txnNumber ? kStartTransactionOption | kMultiStatementTransactionOption : kNoOptions,
@@ -244,7 +245,8 @@ int runQueryWithReadCommands(DBClientBase* conn,
int count = cursorResponse.getBatch().size();
if (objOut) {
- invariant(qr->getLimit() && *qr->getLimit() == 1 && qr->isSingleBatch());
+ invariant(findCommand->getLimit() && *findCommand->getLimit() == 1 &&
+ findCommand->getSingleBatch());
// Since this is a "single batch" query, we can simply grab the first item in the result set
// and return here.
*objOut = (count > 0) ? cursorResponse.getBatch()[0] : BSONObj();
@@ -255,11 +257,11 @@ int runQueryWithReadCommands(DBClientBase* conn,
sleepFor(delayBeforeGetMore);
GetMoreRequest getMoreRequest(
- qr->nss(),
+ findCommand->getNamespaceOrUUID().nss().value_or(NamespaceString()),
cursorResponse.getCursorId(),
- qr->getBatchSize()
- ? boost::optional<std::int64_t>(static_cast<std::int64_t>(*qr->getBatchSize()))
- : boost::none,
+ findCommand->getBatchSize() ? boost::optional<std::int64_t>(static_cast<std::int64_t>(
+ *findCommand->getBatchSize()))
+ : boost::none,
boost::none, // maxTimeMS
boost::none, // term
boost::none); // lastKnownCommittedOpTime
@@ -291,16 +293,17 @@ void doNothing(const BSONObj&) {}
Timestamp getLatestClusterTime(DBClientBase* conn) {
// Sort by descending 'ts' in the query to the oplog collection. The first entry will have the
// latest cluster time.
- auto qr = std::make_unique<QueryRequest>(NamespaceString("local.oplog.rs"));
- qr->setSort(BSON("$natural" << -1));
- qr->setLimit(1LL);
- qr->setSingleBatchField(true);
- invariant(qr->validate());
- const auto dbName = qr->nss().db().toString();
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString("local.oplog.rs"));
+ findCommand->setSort(BSON("$natural" << -1));
+ findCommand->setLimit(1LL);
+ findCommand->setSingleBatch(true);
+ invariant(query_request_helper::validateFindCommand(*findCommand));
+ const auto dbName =
+ findCommand->getNamespaceOrUUID().nss().value_or(NamespaceString()).db().toString();
BSONObj oplogResult;
int count = runQueryWithReadCommands(
- conn, boost::none, boost::none, std::move(qr), Milliseconds(0), &oplogResult);
+ conn, boost::none, boost::none, std::move(findCommand), Milliseconds(0), &oplogResult);
uassert(ErrorCodes::OperationFailed,
str::stream() << "Find cmd on the oplog collection failed; reply was: " << oplogResult,
count == 1);
@@ -991,15 +994,15 @@ void BenchRunOp::executeOnce(DBClientBase* conn,
BSONObj fixedQuery = fixQuery(this->query, *state->bsonTemplateEvaluator);
BSONObj result;
if (this->useReadCmd) {
- auto qr = std::make_unique<QueryRequest>(NamespaceString(this->ns));
- qr->setFilter(fixedQuery);
- qr->setProj(this->projection);
- qr->setLimit(1LL);
- qr->setSingleBatchField(true);
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString(this->ns));
+ findCommand->setFilter(fixedQuery);
+ findCommand->setProjection(this->projection);
+ findCommand->setLimit(1LL);
+ findCommand->setSingleBatch(true);
if (config.useSnapshotReads) {
- qr->setReadConcern(readConcernSnapshot);
+ findCommand->setReadConcern(readConcernSnapshot);
}
- invariant(qr->validate());
+ invariant(query_request_helper::validateFindCommand(*findCommand));
BenchRunEventTrace _bret(&state->stats->findOneCounter);
boost::optional<TxnNumber> txnNumberForOp;
@@ -1009,7 +1012,7 @@ void BenchRunOp::executeOnce(DBClientBase* conn,
state->inProgressMultiStatementTxn = true;
}
runQueryWithReadCommands(
- conn, lsid, txnNumberForOp, std::move(qr), Milliseconds(0), &result);
+ conn, lsid, txnNumberForOp, std::move(findCommand), Milliseconds(0), &result);
} else {
BenchRunEventTrace _bret(&state->stats->findOneCounter);
result = conn->findOne(
@@ -1074,17 +1077,17 @@ void BenchRunOp::executeOnce(DBClientBase* conn,
"cannot use 'options' in combination with read commands",
!this->options);
- auto qr = std::make_unique<QueryRequest>(NamespaceString(this->ns));
- qr->setFilter(fixedQuery);
- qr->setProj(this->projection);
+ auto findCommand = std::make_unique<FindCommand>(NamespaceString(this->ns));
+ findCommand->setFilter(fixedQuery);
+ findCommand->setProjection(this->projection);
if (this->skip) {
- qr->setSkip(this->skip);
+ findCommand->setSkip(this->skip);
}
if (this->limit) {
- qr->setLimit(this->limit);
+ findCommand->setLimit(this->limit);
}
if (this->batchSize) {
- qr->setBatchSize(this->batchSize);
+ findCommand->setBatchSize(this->batchSize);
}
BSONObjBuilder readConcernBuilder;
if (config.useSnapshotReads) {
@@ -1098,9 +1101,9 @@ void BenchRunOp::executeOnce(DBClientBase* conn,
conn, state->rng->nextInt32(this->useAClusterTimeWithinPastSeconds));
readConcernBuilder.append("atClusterTime", atClusterTime);
}
- qr->setReadConcern(readConcernBuilder.obj());
+ findCommand->setReadConcern(readConcernBuilder.obj());
- invariant(qr->validate());
+ invariant(query_request_helper::validateFindCommand(*findCommand));
BenchRunEventTrace _bret(&state->stats->queryCounter);
boost::optional<TxnNumber> txnNumberForOp;
@@ -1117,7 +1120,7 @@ void BenchRunOp::executeOnce(DBClientBase* conn,
count = runQueryWithReadCommands(conn,
lsid,
txnNumberForOp,
- std::move(qr),
+ std::move(findCommand),
Milliseconds(delayBeforeGetMore),
nullptr);
} else {