diff options
author | Bernard Gorman <bernard.gorman@gmail.com> | 2019-05-22 13:10:17 +0100 |
---|---|---|
committer | Bernard Gorman <bernard.gorman@gmail.com> | 2019-05-24 15:27:25 +0100 |
commit | ec6f2325a99b6ddd13af6903eed12ced95e4bea8 (patch) | |
tree | f225a28dc123f6e1ca0f32b1fee4202cee051db5 /src/mongo | |
parent | 8d5727273585524a38d4a663b61403a263f7cf3d (diff) | |
download | mongo-ec6f2325a99b6ddd13af6903eed12ced95e4bea8.tar.gz |
SERVER-41238 Allow $$NOW and $$CLUSTER_TIME to be used in the find command
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 30 | ||||
-rw-r--r-- | src/mongo/db/ops/delete_request.h | 4 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_delete.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_delete.h | 3 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_update.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/ops/update_request.h | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variables.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.h | 4 | ||||
-rw-r--r-- | src/mongo/db/query/query_request.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/query/query_request.h | 12 | ||||
-rw-r--r-- | src/mongo/db/query/query_request_test.cpp | 127 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_cmd.cpp | 25 | ||||
-rw-r--r-- | src/mongo/s/write_ops/batched_command_request.h | 4 |
15 files changed, 188 insertions, 80 deletions
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 67f73d6e6ee..4d79ab118cd 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -42,6 +42,7 @@ #include "mongo/db/db_raii.h" #include "mongo/db/exec/working_set_common.h" #include "mongo/db/matcher/extensions_callback_real.h" +#include "mongo/db/pipeline/variables.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/find.h" @@ -62,6 +63,20 @@ namespace { const auto kTermField = "term"_sd; +// Parses the command object to a QueryRequest. 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 = uassertStatusOK( + QueryRequest::makeFromFindCommand(std::move(nss), std::move(cmdObj), isExplain)); + if (!qr->getRuntimeConstants()) { + qr->setRuntimeConstants(Variables::generateRuntimeConstants(opCtx)); + } + return qr; +} + /** * A command for running .find() queries. */ @@ -168,8 +183,7 @@ public: // Parse the command BSON to a QueryRequest. const bool isExplain = true; - auto qr = - uassertStatusOK(QueryRequest::makeFromFindCommand(nss, _request.body, isExplain)); + auto qr = parseCmdObjectToQueryRequest(opCtx, nss, _request.body, isExplain); // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); @@ -239,13 +253,13 @@ public: ServerReadConcernMetrics::get(opCtx)->recordReadConcern( repl::ReadConcernArgs::get(opCtx)); - // Parse the command BSON to a QueryRequest. + // Parse the command BSON to a QueryRequest. Pass in the parsedNss in case _request.body + // does not have a UUID. + auto parsedNss = + NamespaceString{CommandHelpers::parseNsFromCommand(_dbName, _request.body)}; const bool isExplain = false; - // Pass parseNs to makeFromFindCommand in case _request.body does not have a UUID. - auto qr = uassertStatusOK(QueryRequest::makeFromFindCommand( - NamespaceString(CommandHelpers::parseNsFromCommand(_dbName, _request.body)), - _request.body, - isExplain)); + auto qr = + parseCmdObjectToQueryRequest(opCtx, std::move(parsedNss), _request.body, isExplain); // Only allow speculative majority for internal commands that specify the correct flag. uassert(ErrorCodes::ReadConcernMajorityNotEnabled, diff --git a/src/mongo/db/ops/delete_request.h b/src/mongo/db/ops/delete_request.h index 937297b95ae..a49e6eb37b9 100644 --- a/src/mongo/db/ops/delete_request.h +++ b/src/mongo/db/ops/delete_request.h @@ -61,8 +61,8 @@ public: void setSort(const BSONObj& sort) { _sort = sort; } - void setRuntimeConstants(const RuntimeConstants& runtimeConstants) { - _runtimeConstants = runtimeConstants; + void setRuntimeConstants(RuntimeConstants runtimeConstants) { + _runtimeConstants = std::move(runtimeConstants); } void setCollation(const BSONObj& collation) { _collation = collation; diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index 0ce2cbe557a..c0b757fe69e 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -39,7 +39,6 @@ #include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/ops/delete_request.h" #include "mongo/db/query/canonical_query.h" -#include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/util/assert_util.h" @@ -61,17 +60,6 @@ Status ParsedDelete::parseRequest() { // DeleteStage would not return the deleted document. invariant(_request->getProj().isEmpty() || _request->shouldReturnDeleted()); - // Parse the delete request's collation, if present. This will subsequently be used to - // initialize an ExpressionContext for the query. - if (!_request->getCollation().isEmpty()) { - auto collator = CollatorFactoryInterface::get(_opCtx->getServiceContext()) - ->makeFromBSON(_request->getCollation()); - if (!collator.isOK()) { - return collator.getStatus(); - } - _collator = std::move(collator.getValue()); - } - if (CanonicalQuery::isSimpleIdQuery(_request->getQuery())) { return Status::OK(); } @@ -102,8 +90,12 @@ Status ParsedDelete::parseQueryToCQ() { qr->setLimit(1); } - auto expCtx = - make_intrusive<ExpressionContext>(_opCtx, _collator.get(), _request->getRuntimeConstants()); + // If the delete request has runtime constants attached to it, pass them to the QueryRequest. + if (auto& runtimeConstants = _request->getRuntimeConstants()) { + qr->setRuntimeConstants(*runtimeConstants); + } + + const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(qr), diff --git a/src/mongo/db/ops/parsed_delete.h b/src/mongo/db/ops/parsed_delete.h index 724c4a48656..73f4bef19e4 100644 --- a/src/mongo/db/ops/parsed_delete.h +++ b/src/mongo/db/ops/parsed_delete.h @@ -107,9 +107,6 @@ private: // Unowned pointer to the request object that this executor will process. const DeleteRequest* const _request; - // The collator for the parsed delete's expression context. - std::unique_ptr<CollatorInterface> _collator; - // Parsed query object, or NULL if the query proves to be an id hack query. std::unique_ptr<CanonicalQuery> _canonicalQuery; }; diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index 79e1d9ed692..67215128ce0 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -123,8 +123,12 @@ Status ParsedUpdate::parseQueryToCQ() { allowedMatcherFeatures &= ~MatchExpressionParser::AllowedFeatures::kExpr; } - auto expCtx = - make_intrusive<ExpressionContext>(_opCtx, _collator.get(), _request->getRuntimeConstants()); + // If the update request has runtime constants attached to it, pass them to the QueryRequest. + if (auto& runtimeConstants = _request->getRuntimeConstants()) { + qr->setRuntimeConstants(*runtimeConstants); + } + + boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize( _opCtx, std::move(qr), std::move(expCtx), _extensionsCallback, allowedMatcherFeatures); if (statusWithCQ.isOK()) { diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h index e0f99abf1d4..ee30cc6a827 100644 --- a/src/mongo/db/ops/update_request.h +++ b/src/mongo/db/ops/update_request.h @@ -119,8 +119,8 @@ public: return _updateConstants; } - inline void setRuntimeConstants(const RuntimeConstants& runtimeConstants) { - _runtimeConstants = runtimeConstants; + inline void setRuntimeConstants(RuntimeConstants runtimeConstants) { + _runtimeConstants = std::move(runtimeConstants); } inline const boost::optional<RuntimeConstants>& getRuntimeConstants() const { diff --git a/src/mongo/db/pipeline/variables.cpp b/src/mongo/db/pipeline/variables.cpp index 9e7e2c9256e..cf6b81e9605 100644 --- a/src/mongo/db/pipeline/variables.cpp +++ b/src/mongo/db/pipeline/variables.cpp @@ -151,7 +151,7 @@ Value Variables::getValue(Id id, const Document& root) const { } uasserted(51144, - str::stream() << "Buildin variable '$$" << getBuiltinVariableName(id) + str::stream() << "Builtin variable '$$" << getBuiltinVariableName(id) << "' is not available"); MONGO_UNREACHABLE; default: diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index b520db9b29a..0ae841ab6de 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -209,7 +209,8 @@ env.Library( LIBDEPS=[ "$BUILD_DIR/mongo/base", "$BUILD_DIR/mongo/db/repl/read_concern_args", - "$BUILD_DIR/mongo/db/catalog/collection_catalog" + "$BUILD_DIR/mongo/db/catalog/collection_catalog", + "$BUILD_DIR/mongo/db/pipeline/runtime_constants_idl" ], ) diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 0be2f524798..ff77f314fa2 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -151,7 +151,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( // Make MatchExpression. boost::intrusive_ptr<ExpressionContext> newExpCtx; if (!expCtx.get()) { - newExpCtx.reset(new ExpressionContext(opCtx, collator.get())); + newExpCtx.reset(new ExpressionContext(opCtx, collator.get(), qr->getRuntimeConstants())); } else { newExpCtx = expCtx; invariant(CollatorInterface::collatorsMatch(collator.get(), expCtx->getCollator())); diff --git a/src/mongo/db/query/find_and_modify_request.h b/src/mongo/db/query/find_and_modify_request.h index 2ee73859d1b..a8b350e691f 100644 --- a/src/mongo/db/query/find_and_modify_request.h +++ b/src/mongo/db/query/find_and_modify_request.h @@ -167,8 +167,8 @@ public: /** * Sets any constant values which may be required by the query and/or update. */ - void setRuntimeConstants(const RuntimeConstants& runtimeConstants) { - _runtimeConstants = runtimeConstants; + void setRuntimeConstants(RuntimeConstants runtimeConstants) { + _runtimeConstants = std::move(runtimeConstants); } /** diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp index a8698404ea8..c43317b584b 100644 --- a/src/mongo/db/query/query_request.cpp +++ b/src/mongo/db/query/query_request.cpp @@ -98,6 +98,7 @@ const char kOplogReplayField[] = "oplogReplay"; const char kNoCursorTimeoutField[] = "noCursorTimeout"; const char kAwaitDataField[] = "awaitData"; const char kPartialResultsField[] = "allowPartialResults"; +const char kRuntimeConstantsField[] = "runtimeConstants"; const char kTermField[] = "term"; const char kOptionsField[] = "options"; const char kReadOnceField[] = "readOnce"; @@ -337,6 +338,14 @@ StatusWith<unique_ptr<QueryRequest>> QueryRequest::parseFromFindCommand(unique_p } qr->_allowPartialResults = el.boolean(); + } else if (fieldName == kRuntimeConstantsField) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; + } + qr->_runtimeConstants = + RuntimeConstants::parse(IDLParserErrorContext(kRuntimeConstantsField), + cmdObj.getObjectField(kRuntimeConstantsField)); } else if (fieldName == kOptionsField) { // 3.0.x versions of the shell may generate an explain of a find command with an // 'options' field. We accept this only if the 'options' field is empty so that @@ -544,6 +553,12 @@ void QueryRequest::asFindCommandInternal(BSONObjBuilder* cmdBuilder) const { cmdBuilder->append(kPartialResultsField, true); } + if (_runtimeConstants) { + BSONObjBuilder rtcBuilder(cmdBuilder->subobjStart(kRuntimeConstantsField)); + _runtimeConstants->serialize(&rtcBuilder); + rtcBuilder.doneFast(); + } + if (_replicationTerm) { cmdBuilder->append(kTermField, *_replicationTerm); } @@ -1116,6 +1131,11 @@ StatusWith<BSONObj> QueryRequest::asAggregationCommand() const { if (!_unwrappedReadPref.isEmpty()) { aggregationBuilder.append(QueryRequest::kUnwrappedReadPrefField, _unwrappedReadPref); } + if (_runtimeConstants) { + BSONObjBuilder rtcBuilder(aggregationBuilder.subobjStart(kRuntimeConstantsField)); + _runtimeConstants->serialize(&rtcBuilder); + rtcBuilder.doneFast(); + } return StatusWith<BSONObj>(aggregationBuilder.obj()); } } // namespace mongo diff --git a/src/mongo/db/query/query_request.h b/src/mongo/db/query/query_request.h index c87d9f951e3..ade62c52ddf 100644 --- a/src/mongo/db/query/query_request.h +++ b/src/mongo/db/query/query_request.h @@ -36,6 +36,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" +#include "mongo/db/pipeline/runtime_constants_gen.h" #include "mongo/db/query/tailable_mode.h" namespace mongo { @@ -329,6 +330,14 @@ public: return _tailableMode; } + void setRuntimeConstants(RuntimeConstants runtimeConstants) { + _runtimeConstants = std::move(runtimeConstants); + } + + const boost::optional<RuntimeConstants>& getRuntimeConstants() const { + return _runtimeConstants; + } + bool isSlaveOk() const { return _slaveOk; } @@ -514,6 +523,9 @@ private: bool _showRecordId = false; bool _hasReadPref = false; + // Runtime constants which may be referenced by $expr, if present. + boost::optional<RuntimeConstants> _runtimeConstants; + // Options that can be specified in the OP_QUERY 'flags' header. TailableModeEnum _tailableMode = TailableModeEnum::kNormal; bool _slaveOk = false; diff --git a/src/mongo/db/query/query_request_test.cpp b/src/mongo/db/query/query_request_test.cpp index 3af9d96921e..0870bf245da 100644 --- a/src/mongo/db/query/query_request_test.cpp +++ b/src/mongo/db/query/query_request_test.cpp @@ -449,19 +449,22 @@ TEST(QueryRequestTest, ParseFromCommandCommentWithValidMinMax) { } TEST(QueryRequestTest, ParseFromCommandAllNonOptionFields) { + RuntimeConstants rtc{Date_t::now(), Timestamp(1, 1)}; + BSONObj rtcObj = BSON("runtimeConstants" << rtc.toBSON()); BSONObj cmdObj = fromjson( - "{find: 'testns'," - "filter: {a: 1}," - "sort: {b: 1}," - "projection: {c: 1}," - "hint: {d: 1}," - "readConcern: {e: 1}," - "$queryOptions: {$readPreference: 'secondary'}," - "collation: {f: 1}," - "limit: 3," - "skip: 5," - "batchSize: 90," - "singleBatch: false}"); + "{find: 'testns'," + "filter: {a: 1}," + "sort: {b: 1}," + "projection: {c: 1}," + "hint: {d: 1}," + "readConcern: {e: 1}," + "$queryOptions: {$readPreference: 'secondary'}," + "collation: {f: 1}," + "limit: 3," + "skip: 5," + "batchSize: 90," + "singleBatch: false}") + .addField(rtcObj["runtimeConstants"]); const NamespaceString nss("test.testns"); bool isExplain = false; unique_ptr<QueryRequest> qr( @@ -486,6 +489,9 @@ TEST(QueryRequestTest, ParseFromCommandAllNonOptionFields) { ASSERT_EQUALS(3, *qr->getLimit()); ASSERT_EQUALS(5, *qr->getSkip()); ASSERT_EQUALS(90, *qr->getBatchSize()); + ASSERT(qr->getRuntimeConstants().has_value()); + ASSERT_EQUALS(qr->getRuntimeConstants()->getLocalNow(), rtc.getLocalNow()); + ASSERT_EQUALS(qr->getRuntimeConstants()->getClusterTime(), rtc.getClusterTime()); ASSERT(qr->wantMore()); } @@ -788,6 +794,33 @@ TEST(QueryRequestTest, ParseFromCommandReadOnceWrongType) { auto result = QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain); ASSERT_EQ(ErrorCodes::FailedToParse, result.getStatus()); } + +TEST(QueryRequestTest, ParseFromCommandRuntimeConstantsWrongType) { + BSONObj cmdObj = BSON("find" + << "testns" + << "runtimeConstants" + << "shouldNotBeString"); + const NamespaceString nss("test.testns"); + bool isExplain = false; + auto result = QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain); + ASSERT_EQ(ErrorCodes::FailedToParse, result.getStatus()); +} + +TEST(QueryRequestTest, ParseFromCommandRuntimeConstantsSubfieldsWrongType) { + BSONObj cmdObj = BSON("find" + << "testns" + << "runtimeConstants" + << BSON("localNow" + << "shouldBeDate" + << "clusterTime" + << "shouldBeTimestamp")); + const NamespaceString nss("test.testns"); + bool isExplain = false; + ASSERT_THROWS_CODE(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain), + AssertionException, + ErrorCodes::TypeMismatch); +} + // // Parsing errors where a field has the right type but a bad value. // @@ -880,18 +913,21 @@ TEST(QueryRequestTest, ParseFromCommandDefaultBatchSize) { // TEST(QueryRequestTest, AsFindCommandAllNonOptionFields) { + BSONObj rtcObj = + BSON("runtimeConstants" << (RuntimeConstants{Date_t::now(), Timestamp(1, 1)}.toBSON())); BSONObj cmdObj = fromjson( - "{find: 'testns'," - "filter: {a: 1}," - "projection: {c: 1}," - "sort: {b: 1}," - "hint: {d: 1}," - "readConcern: {e: 1}," - "collation: {f: 1}," - "skip: 5," - "limit: 3," - "batchSize: 90," - "singleBatch: true}"); + "{find: 'testns'," + "filter: {a: 1}," + "projection: {c: 1}," + "sort: {b: 1}," + "hint: {d: 1}," + "readConcern: {e: 1}," + "collation: {f: 1}," + "skip: 5," + "limit: 3," + "batchSize: 90," + "singleBatch: true}") + .addField(rtcObj["runtimeConstants"]); const NamespaceString nss("test.testns"); bool isExplain = false; unique_ptr<QueryRequest> qr( @@ -900,19 +936,23 @@ TEST(QueryRequestTest, AsFindCommandAllNonOptionFields) { } TEST(QueryRequestTest, AsFindCommandWithUuidAllNonOptionFields) { - BSONObj cmdObj = fromjson( - // This binary value is UUID("01234567-89ab-cdef-edcb-a98765432101") - "{find: { \"$binary\" : \"ASNFZ4mrze/ty6mHZUMhAQ==\", \"$type\" : \"04\" }," - "filter: {a: 1}," - "projection: {c: 1}," - "sort: {b: 1}," - "hint: {d: 1}," - "readConcern: {e: 1}," - "collation: {f: 1}," - "skip: 5," - "limit: 3," - "batchSize: 90," - "singleBatch: true}"); + BSONObj rtcObj = + BSON("runtimeConstants" << (RuntimeConstants{Date_t::now(), Timestamp(1, 1)}.toBSON())); + BSONObj cmdObj = + fromjson( + // This binary value is UUID("01234567-89ab-cdef-edcb-a98765432101") + "{find: { \"$binary\" : \"ASNFZ4mrze/ty6mHZUMhAQ==\", \"$type\" : \"04\" }," + "filter: {a: 1}," + "projection: {c: 1}," + "sort: {b: 1}," + "hint: {d: 1}," + "readConcern: {e: 1}," + "collation: {f: 1}," + "skip: 5," + "limit: 3," + "batchSize: 90," + "singleBatch: true}") + .addField(rtcObj["runtimeConstants"]); const NamespaceString nss("test.testns"); bool isExplain = false; unique_ptr<QueryRequest> qr( @@ -1049,6 +1089,7 @@ TEST(QueryRequestTest, DefaultQueryParametersCorrect) { ASSERT_EQUALS(false, qr->isTailableAndAwaitData()); ASSERT_EQUALS(false, qr->isExhaust()); ASSERT_EQUALS(false, qr->isAllowPartialResults()); + ASSERT_EQUALS(false, qr->getRuntimeConstants().has_value()); } // @@ -1330,6 +1371,20 @@ TEST(QueryRequestTest, ConvertToAggregationWithAllowSpeculativeMajorityReadFails ASSERT_EQ(ErrorCodes::InvalidPipelineOperator, aggCmd.getStatus().code()); } +TEST(QueryRequestTest, ConvertToAggregationWithRuntimeConstantsSucceeds) { + RuntimeConstants rtc{Date_t::now(), Timestamp(1, 1)}; + QueryRequest qr(testns); + qr.setRuntimeConstants(rtc); + auto agg = qr.asAggregationCommand(); + ASSERT_OK(agg); + + auto ar = AggregationRequest::parseFromBSON(testns, agg.getValue()); + ASSERT_OK(ar.getStatus()); + ASSERT(ar.getValue().getRuntimeConstants().has_value()); + ASSERT_EQ(ar.getValue().getRuntimeConstants()->getLocalNow(), rtc.getLocalNow()); + ASSERT_EQ(ar.getValue().getRuntimeConstants()->getClusterTime(), rtc.getClusterTime()); +} + TEST(QueryRequestTest, ParseFromLegacyObjMetaOpComment) { BSONObj queryObj = fromjson( "{$query: {a: 1}," diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index e3c0461931f..dd726a64cc6 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -55,6 +55,20 @@ using std::vector; const char kTermField[] = "term"; +// Parses the command object to a QueryRequest, 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 = uassertStatusOK( + QueryRequest::makeFromFindCommand(std::move(nss), std::move(cmdObj), isExplain)); + uassert( + 51202, "Cannot specify runtime constants option to a mongos", !qr->getRuntimeConstants()); + qr->setRuntimeConstants(Variables::generateRuntimeConstants(opCtx)); + return qr; +} + /** * Implements the find command on mongos. */ @@ -122,12 +136,12 @@ public: ExplainOptions::Verbosity verbosity, rpc::ReplyBuilderInterface* result) override { // Parse the command BSON to a QueryRequest. - bool isExplain = true; - auto qr = - uassertStatusOK(QueryRequest::makeFromFindCommand(ns(), _request.body, isExplain)); + const bool isExplain = true; + auto qr = parseCmdObjectToQueryRequest(opCtx, ns(), _request.body, isExplain); try { - const auto explainCmd = ClusterExplain::wrapAsExplain(_request.body, verbosity); + const auto explainCmd = + ClusterExplain::wrapAsExplain(qr->asFindCommand(), verbosity); long long millisElapsed; std::vector<AsyncRequestsSender::Response> shardResponses; @@ -185,8 +199,7 @@ public: globalOpCounters.gotQuery(); const bool isExplain = false; - auto qr = - uassertStatusOK(QueryRequest::makeFromFindCommand(ns(), _request.body, isExplain)); + auto qr = parseCmdObjectToQueryRequest(opCtx, ns(), _request.body, isExplain); const boost::intrusive_ptr<ExpressionContext> expCtx; auto cq = uassertStatusOK( diff --git a/src/mongo/s/write_ops/batched_command_request.h b/src/mongo/s/write_ops/batched_command_request.h index 1c454adaecc..b49e893e5aa 100644 --- a/src/mongo/s/write_ops/batched_command_request.h +++ b/src/mongo/s/write_ops/batched_command_request.h @@ -115,9 +115,9 @@ public: return *_shardVersion; } - void setRuntimeConstants(const RuntimeConstants& runtimeConstants) { + void setRuntimeConstants(RuntimeConstants runtimeConstants) { invariant(_updateReq); - _updateReq->setRuntimeConstants(runtimeConstants); + _updateReq->setRuntimeConstants(std::move(runtimeConstants)); } bool hasRuntimeConstants() const { |