summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@mongodb.com>2023-04-13 21:47:43 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-04-17 18:36:58 +0000
commit7ed14a4b2c043c639d1c6aa4d22f80f30ca44d97 (patch)
treeef4afef9c6bf01061e17a701b7cc2f24d7863eeb
parent2774750311fde8495049d5ea609f70be241dad75 (diff)
downloadmongo-7ed14a4b2c043c639d1c6aa4d22f80f30ca44d97.tar.gz
SERVER-75356 Fix sharded explain path's handling of 'let' parameters
(cherry picked from commit 33e6eec5978a20a4b227c36f26b0ae909e8e6728)
-rw-r--r--etc/backports_required_for_multiversion_tests.yml4
-rw-r--r--jstests/core/command_let_variables.js356
-rw-r--r--src/mongo/db/pipeline/process_interface/mongos_process_interface.cpp11
-rw-r--r--src/mongo/db/pipeline/sharded_agg_helpers.cpp2
-rw-r--r--src/mongo/db/s/sessions_collection_config_server.cpp6
-rw-r--r--src/mongo/db/s/shardsvr_drop_indexes_command.cpp6
-rw-r--r--src/mongo/s/cluster_commands_helpers.cpp60
-rw-r--r--src/mongo/s/cluster_commands_helpers.h26
-rw-r--r--src/mongo/s/commands/cluster_analyze_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_coll_stats_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_count_cmd.h8
-rw-r--r--src/mongo/s/commands/cluster_create_indexes_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_data_size_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_distinct_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_filemd5_cmd.cpp4
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.h4
-rw-r--r--src/mongo/s/commands/cluster_index_filter_cmd.cpp4
-rw-r--r--src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp4
-rw-r--r--src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_validate_cmd.cpp6
21 files changed, 376 insertions, 167 deletions
diff --git a/etc/backports_required_for_multiversion_tests.yml b/etc/backports_required_for_multiversion_tests.yml
index e3ba6578f08..eeecdb16915 100644
--- a/etc/backports_required_for_multiversion_tests.yml
+++ b/etc/backports_required_for_multiversion_tests.yml
@@ -364,6 +364,8 @@ last-continuous:
ticket: SERVER-67180
- test_file: jstests/core/clustered/clustered_collection_hint.js
ticket: SERVER-73482
+ - test_file: jstests/core/command_let_variables.js
+ ticket: SERVER-75356
suites: null
last-lts:
all:
@@ -807,4 +809,6 @@ last-lts:
ticket: SERVER-75886
- test_file: jstests/core/clustered/clustered_collection_hint.js
ticket: SERVER-73482
+ - test_file: jstests/core/command_let_variables.js
+ ticket: SERVER-75356
suites: null
diff --git a/jstests/core/command_let_variables.js b/jstests/core/command_let_variables.js
index 1e4286dbc19..e608bda6f5d 100644
--- a/jstests/core/command_let_variables.js
+++ b/jstests/core/command_let_variables.js
@@ -6,13 +6,15 @@
(function() {
"use strict";
+load("jstests/libs/analyze_plan.js");
load("jstests/libs/fixture_helpers.js"); // For 'isMongos' and 'isSharded'.
const testDB = db.getSiblingDB("command_let_variables");
const coll = testDB.command_let_variables;
-const targetColl = testDB.command_let_variables_target;
+coll.drop();
-assert.commandWorked(testDB.dropDatabase());
+const isMongos = FixtureHelpers.isMongos(testDB);
+const isCollSharded = FixtureHelpers.isSharded(coll);
const testDocs = [
{
@@ -82,7 +84,20 @@ expectedResults = [
assert.eq(coll.aggregate(pipeline, {let : {target_trend: "weak decline"}}).toArray(),
expectedResults);
-if (!FixtureHelpers.isMongos(testDB)) {
+// Test that running explain on the agg command works as expected.
+let explain = assert.commandWorked(testDB.runCommand({
+ explain:
+ {aggregate: coll.getName(), pipeline, let : {target_trend: "weak decline"}, cursor: {}},
+ verbosity: "executionStats"
+}));
+if (!isMongos) {
+ assert(explain.hasOwnProperty("stages"), explain);
+ assert.neq(explain.stages.length, 0, explain);
+ let lastStage = explain.stages[explain.stages.length - 1];
+ assert.eq(lastStage.nReturned, 2, explain);
+}
+
+if (!isMongos) {
// Test that if runtimeConstants and let are both specified, both will coexist.
// Runtime constants are not allowed on mongos passthroughs.
let constants = {
@@ -262,33 +277,77 @@ expectedResults = {
assert.eq(result.length, 1);
assert.eq(expectedResults, result[0]);
-// Delete tests with let params will delete a record, assert that a point-wise find yields an empty
-// result, and then restore the collection state for further tests down the line. We can't exercise
-// a multi-delete here (limit: 0) because of failures in sharded txn passthrough tests.
-assert.commandWorked(testDB.runCommand({
- delete: coll.getName(),
- let : {target_species: "Song Thrush (Turdus philomelos)"},
- deletes: [{q: {$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]}, limit: 1}]
+// Test that let parameters work as expected when the find is run as an explain.
+explain = assert.commandWorked(testDB.runCommand({
+ explain: {
+ find: coll.getName(),
+ let : {target_species: "Song Thrush (Turdus philomelos)"},
+ filter: {$expr: {$eq: ["$Species", "$$target_species"]}},
+ projection: {_id: 0}
+ },
+ verbosity: "executionStats"
}));
+if (!isMongos) {
+ assert.eq(explain.executionStats.nReturned, 1, explain);
+}
-result = assert
- .commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}}))
- .cursor.firstBatch;
-assert.eq(result.length, 0);
+// TODO SERVER-76037: Write commands commands do not currently work with 'let' parameters when
+// 'featureFlagUpdateOneWithoutShardKey' is enabled.
+const skipWriteCmdTests = (function() {
+ const featureFlagName = "featureFlagUpdateOneWithoutShardKey";
+ // Don't assert that the command succeeded, since we expect it to fail if the parameter does not
+ // exist
+ const featureFlagParam = db.adminCommand({getParameter: 1, [featureFlagName]: 1});
+ return isCollSharded && featureFlagParam.hasOwnProperty(featureFlagName) &&
+ featureFlagParam[featureFlagName].value;
+}());
+if (!skipWriteCmdTests) {
+ // Delete tests with let params will delete a record, assert that a point-wise find yields an
+ // empty result, and then restore the collection state for further tests down the line. We can't
+ // exercise a multi-delete here (limit: 0) because of failures in sharded txn passthrough tests.
+ assert.commandWorked(testDB.runCommand({
+ delete: coll.getName(),
+ let : {target_species: "Song Thrush (Turdus philomelos)"},
+ deletes:
+ [{q: {$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]}, limit: 1}]
+ }));
-// Test that the .remove() shell helper supports let parameters.
-assert.commandWorked(coll.insert({_id: 4, Species: "bird_to_remove"}));
-result = assert.commandWorked(
- coll.remove({$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]},
- {justOne: true, let : {target_species: "bird_to_remove"}}));
-assert.eq(result.nRemoved, 1);
+ result = assert
+ .commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}}))
+ .cursor.firstBatch;
+ assert.eq(result.length, 0);
+
+ assert.commandWorked(coll.insert({_id: 4, Species: "bird_to_remove"}));
+
+ // Test that explain of a delete command works as expected with 'let' parameters.
+ explain = assert.commandWorked(testDB.runCommand({
+ explain: {
+ delete: coll.getName(),
+ let : {target_species: "bird_to_remove"},
+ deletes: [
+ {q: {$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]}, limit: 1}
+ ]
+ },
+ verbosity: "executionStats"
+ }));
+ if (!isMongos) {
+ let deleteStage = getPlanStage(explain.executionStats.executionStages, "DELETE");
+ assert.eq(deleteStage.nWouldDelete, 1, explain);
+ }
-result = assert
- .commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}}))
- .cursor.firstBatch;
-assert.eq(result.length, 0);
+ // Test that the .remove() shell helper supports let parameters.
+ result = assert.commandWorked(
+ coll.remove({$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]},
+ {justOne: true, let : {target_species: "bird_to_remove"}}));
+ assert.eq(result.nRemoved, 1);
+
+ result = assert
+ .commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}}))
+ .cursor.firstBatch;
+ assert.eq(result.length, 0);
+}
// Test that reserved names are not allowed as let variable names.
assert.commandFailedWithCode(
@@ -333,113 +392,155 @@ assert.commandWorked(testDB.runCommand({
cursor: {}
}));
-// Test that findAndModify works correctly with let parameter arguments.
assert.commandWorked(coll.insert({_id: 5, Species: "spy_bird"}));
-result = testDB.runCommand({
- findAndModify: coll.getName(),
- let : {target_species: "spy_bird"},
- // Querying on _id field for sharded collection passthroughs.
- query: {$and: [{_id: 5}, {$expr: {$eq: ["$Species", "$$target_species"]}}]},
- update: {Species: "questionable_bird"},
- new: true
-});
-expectedResults = {
- _id: 5,
- Species: "questionable_bird"
-};
-assert.eq(expectedResults, result.value, result);
-
-result = testDB.runCommand({
- findAndModify: coll.getName(),
- let : {species_name: "not_a_bird", realSpecies: "dino"},
- // Querying on _id field for sharded collection passthroughs.
- query: {$and: [{_id: 5}, {$expr: {$eq: ["$Species", "questionable_bird"]}}]},
- update: [{$project: {Species: "$$species_name"}}, {$addFields: {suspect: "$$realSpecies"}}],
- new: true
-});
-expectedResults = {
- _id: 5,
- Species: "not_a_bird",
- suspect: "dino"
-};
-assert.eq(expectedResults, result.value, result);
-
-// Test that update respects different parameters in both the query and update part.
-result = assert.commandWorked(testDB.runCommand({
- update: coll.getName(),
- updates: [
- {q: {$expr: {$eq: ["$Species", "$$target_species"]}}, u: [{$set: {Species: "$$new_name"}}]}
- ],
- let : {target_species: "Chaffinch (Fringilla coelebs)", new_name: "Chaffinch"}
-}));
-assert.eq(result.n, 1);
-assert.eq(result.nModified, 1);
-
-result = assert.commandWorked(testDB.runCommand(
- {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch (Fringilla coelebs)"]}}}));
-assert.eq(result.cursor.firstBatch.length, 0);
-
-result = assert.commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
-assert.eq(result.cursor.firstBatch.length, 1);
-
-// Test that update respects runtime constants and parameters.
-result = assert.commandWorked(testDB.runCommand({
- update: coll.getName(),
- updates: [{
- q: {$expr: {$eq: ["$Species", "$$target_species"]}},
- u: [{$set: {Timestamp: "$$NOW"}}, {$set: {Species: "$$new_name"}}]
- }],
- let : {target_species: "Chaffinch", new_name: "Pied Piper"}
-}));
-assert.eq(result.n, 1);
-assert.eq(result.nModified, 1);
-result = assert.commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
-assert.eq(result.cursor.firstBatch.length, 0, result);
+// TODO SERVER-76037: Re-enable these test cases in all contexts.
+if (!skipWriteCmdTests) {
+ // Test that explain of findAndModify works correctly with let parameters.
+ explain = assert.commandWorked(testDB.runCommand({
+ explain: {
+ findAndModify: coll.getName(),
+ let : {target_species: "spy_bird"},
+ // Querying on _id field for sharded collection passthroughs.
+ query: {$and: [{_id: 5}, {$expr: {$eq: ["$Species", "$$target_species"]}}]},
+ update: {Species: "questionable_bird"},
+ new: true
+ },
+ verbosity: "executionStats"
+ }));
+ if (!isMongos) {
+ let updateStage = getPlanStage(explain.executionStats.executionStages, "UPDATE");
+ assert.eq(updateStage.nMatched, 1, explain);
+ assert.eq(updateStage.nWouldModify, 1, explain);
+ }
+
+ // Test that findAndModify works correctly with let parameter arguments.
+ result = assert.commandWorked(testDB.runCommand({
+ findAndModify: coll.getName(),
+ let : {target_species: "spy_bird"},
+ // Querying on _id field for sharded collection passthroughs.
+ query: {$and: [{_id: 5}, {$expr: {$eq: ["$Species", "$$target_species"]}}]},
+ update: {Species: "questionable_bird"},
+ new: true
+ }));
+ expectedResults = {_id: 5, Species: "questionable_bird"};
+ assert.eq(expectedResults, result.value, result);
+
+ result = assert.commandWorked(testDB.runCommand({
+ findAndModify: coll.getName(),
+ let : {species_name: "not_a_bird", realSpecies: "dino"},
+ // Querying on _id field for sharded collection passthroughs.
+ query: {$and: [{_id: 5}, {$expr: {$eq: ["$Species", "questionable_bird"]}}]},
+ update: [{$project: {Species: "$$species_name"}}, {$addFields: {suspect: "$$realSpecies"}}],
+ new: true
+ }));
+ expectedResults = {_id: 5, Species: "not_a_bird", suspect: "dino"};
+ assert.eq(expectedResults, result.value, result);
+
+ // Test that explain of update works correctly with let parameters.
+ explain = assert.commandWorked(testDB.runCommand({
+ explain: {
+ update: coll.getName(),
+ updates: [{
+ q: {_id: 3, $expr: {$eq: ["$Species", "$$target_species"]}},
+ u: [{$set: {Species: "$$new_name"}}],
+ }],
+ let : {target_species: "Chaffinch (Fringilla coelebs)", new_name: "Chaffinch"}
+ },
+ verbosity: "executionStats"
+ }));
+ if (!isMongos) {
+ let updateStage = getPlanStage(explain.executionStats.executionStages, "UPDATE");
+ assert.eq(updateStage.nMatched, 1, explain);
+ assert.eq(updateStage.nWouldModify, 1, explain);
+ }
-result = assert.commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Pied Piper"]}}}));
-assert.eq(result.cursor.firstBatch.length, 1, result);
+ // Test that update respects different parameters in both the query and update part.
+ result = assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {_id: 3, $expr: {$eq: ["$Species", "$$target_species"]}},
+ u: [{$set: {Species: "$$new_name"}}],
+ }],
+ let : {target_species: "Chaffinch (Fringilla coelebs)", new_name: "Chaffinch"}
+ }));
+ assert.eq(result.n, 1);
+ assert.eq(result.nModified, 1);
-// Test that undefined let params in the update's query part fail gracefully.
-assert.commandFailedWithCode(testDB.runCommand({
- update: coll.getName(),
- updates: [{
- q: {$expr: {$eq: ["$Species", "$$target_species"]}},
- u: [{$set: {Species: "Homo Erectus"}}]
- }],
- let : {cat: "not_a_bird"}
-}),
- 17276);
+ result = assert.commandWorked(testDB.runCommand({
+ find: coll.getName(),
+ filter: {$expr: {$eq: ["$Species", "Chaffinch (Fringilla coelebs)"]}}
+ }));
+ assert.eq(result.cursor.firstBatch.length, 0);
+
+ result = assert.commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
+ assert.eq(result.cursor.firstBatch.length, 1);
+
+ // Test that update respects runtime constants and parameters.
+ result = assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {_id: 3, $expr: {$eq: ["$Species", "$$target_species"]}},
+ u: [{$set: {Timestamp: "$$NOW"}}, {$set: {Species: "$$new_name"}}],
+ }],
+ let : {target_species: "Chaffinch", new_name: "Pied Piper"}
+ }));
+ assert.eq(result.n, 1);
+ assert.eq(result.nModified, 1);
-// Test that undefined let params in the update's update part fail gracefully.
-assert.commandFailedWithCode(testDB.runCommand({
- update: coll.getName(),
- updates: [{
- q: {$expr: {$eq: ["$Species", "Chaffinch (Fringilla coelebs)"]}},
- u: [{$set: {Species: "$$new_name"}}]
- }],
- let : {cat: "not_a_bird"}
-}),
- 17276);
+ result = assert.commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
+ assert.eq(result.cursor.firstBatch.length, 0, result);
-// Test that the .update() shell helper supports let parameters.
-result = assert.commandWorked(
- coll.update({$expr: {$eq: ["$Species", "$$target_species"]}},
- [{$set: {Species: "$$new_name"}}],
- {let : {target_species: "Pied Piper", new_name: "Chaffinch"}}));
-assert.eq(result.nMatched, 1);
-assert.eq(result.nModified, 1);
+ result = assert.commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Pied Piper"]}}}));
+ assert.eq(result.cursor.firstBatch.length, 1, result);
-result = assert.commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Pied Piper"]}}}));
-assert.eq(result.cursor.firstBatch.length, 0, result);
+ // This forces a multi-statement transaction to commit if this test is running in one of the
+ // multi-statement transaction passthrough suites. We need to do this to ensure the updates
+ // above commit before running an update that will fail, as the failed update aborts the entire
+ // transaction and rolls back the updates above.
+ assert.commandWorked(testDB.runCommand({ping: 1}));
-result = assert.commandWorked(
- testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
-assert.eq(result.cursor.firstBatch.length, 1, result);
+ // Test that undefined let params in the update's query part fail gracefully.
+ assert.commandFailedWithCode(testDB.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {$expr: {$eq: ["$Species", "$$target_species"]}},
+ u: [{$set: {Species: "Homo Erectus"}}]
+ }],
+ let : {cat: "not_a_bird"}
+ }),
+ 17276);
+
+ // Test that undefined let params in the update's update part fail gracefully.
+ assert.commandFailedWithCode(testDB.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {_id: 3, $expr: {$eq: ["$Species", "Chaffinch (Fringilla coelebs)"]}},
+ u: [{$set: {Species: "$$new_name"}}],
+ }],
+ let : {cat: "not_a_bird"}
+ }),
+ 17276);
+
+ // Test that the .update() shell helper supports let parameters.
+ result = assert.commandWorked(
+ coll.update({_id: 3, $expr: {$eq: ["$Species", "$$target_species"]}},
+ [{$set: {Species: "$$new_name"}}],
+ {let : {target_species: "Pied Piper", new_name: "Chaffinch"}}));
+ assert.eq(result.nMatched, 1);
+ assert.eq(result.nModified, 1);
+
+ result = assert.commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Pied Piper"]}}}));
+ assert.eq(result.cursor.firstBatch.length, 0, result);
+
+ result = assert.commandWorked(testDB.runCommand(
+ {find: coll.getName(), filter: {$expr: {$eq: ["$Species", "Chaffinch"]}}}));
+ assert.eq(result.cursor.firstBatch.length, 1, result);
+}
// Test that let variables can be initialized with an expression.
result = assert
@@ -519,7 +620,10 @@ assert.between(0, result, 1);
}
// Test that the expressions are evaluated once up front.
-{
+//
+// TODO SERVER-75927: This does not work as expected when the collection is sharded. Once the bug
+// is fixed, we should re-enable this test case when the collection is sharded.
+if (!isCollSharded) {
const values = assert
.commandWorked(testDB.runCommand({
find: coll.getName(),
diff --git a/src/mongo/db/pipeline/process_interface/mongos_process_interface.cpp b/src/mongo/db/pipeline/process_interface/mongos_process_interface.cpp
index 18e2f11ee1b..be0bb849391 100644
--- a/src/mongo/db/pipeline/process_interface/mongos_process_interface.cpp
+++ b/src/mongo/db/pipeline/process_interface/mongos_process_interface.cpp
@@ -201,8 +201,15 @@ boost::optional<Document> MongosProcessInterface::lookupSingleDocument(
// single shard will be targeted here; however, in certain cases where only the _id
// is present, we may need to scatter-gather the query to all shards in order to
// find the document.
- auto requests = getVersionedRequestsForTargetedShards(
- expCtx->opCtx, nss, cri, findCmd, filterObj, CollationSpec::kSimpleSpec);
+ auto requests =
+ getVersionedRequestsForTargetedShards(expCtx->opCtx,
+ nss,
+ cri,
+ findCmd,
+ filterObj,
+ CollationSpec::kSimpleSpec,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
// Dispatch the requests. The 'establishCursors' method conveniently prepares the
// result into a vector of cursor responses for us.
diff --git a/src/mongo/db/pipeline/sharded_agg_helpers.cpp b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
index 8e5fb369e79..c51142298ed 100644
--- a/src/mongo/db/pipeline/sharded_agg_helpers.cpp
+++ b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
@@ -1192,7 +1192,7 @@ DispatchShardPipelineResults dispatchShardPipeline(
// shards, and should participate in the shard version protocol.
invariant(executionNsRoutingInfo);
shardResults =
- scatterGatherVersionedTargetByRoutingTable(opCtx,
+ scatterGatherVersionedTargetByRoutingTable(expCtx,
expCtx->ns.db(),
expCtx->ns,
*executionNsRoutingInfo,
diff --git a/src/mongo/db/s/sessions_collection_config_server.cpp b/src/mongo/db/s/sessions_collection_config_server.cpp
index 4e9ebb06578..8aa967d33cb 100644
--- a/src/mongo/db/s/sessions_collection_config_server.cpp
+++ b/src/mongo/db/s/sessions_collection_config_server.cpp
@@ -99,8 +99,10 @@ void SessionsCollectionConfigServer::_generateIndexesIfNeeded(OperationContext*
SessionsCollection::generateCreateIndexesCmd(),
ReadPreferenceSetting(ReadPreference::PrimaryOnly),
Shard::RetryPolicy::kNoRetry,
- BSONObj() /* query */,
- BSONObj() /* collation */);
+ BSONObj() /*query*/,
+ BSONObj() /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
});
for (auto& shardResult : shardResults) {
diff --git a/src/mongo/db/s/shardsvr_drop_indexes_command.cpp b/src/mongo/db/s/shardsvr_drop_indexes_command.cpp
index a50ace9a5ae..0a552d680a0 100644
--- a/src/mongo/db/s/shardsvr_drop_indexes_command.cpp
+++ b/src/mongo/db/s/shardsvr_drop_indexes_command.cpp
@@ -201,8 +201,10 @@ ShardsvrDropIndexesCommand::Invocation::Response ShardsvrDropIndexesCommand::Inv
CommandHelpers::filterCommandRequestForPassthrough(cmdToBeSent)),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kNotIdempotent,
- BSONObj() /* query */,
- BSONObj() /* collation */);
+ BSONObj() /*query*/,
+ BSONObj() /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
// Append responses we've received from previous retries of this operation due to a
// stale config error.
diff --git a/src/mongo/s/cluster_commands_helpers.cpp b/src/mongo/s/cluster_commands_helpers.cpp
index 345c4eae3f7..1619df5129f 100644
--- a/src/mongo/s/cluster_commands_helpers.cpp
+++ b/src/mongo/s/cluster_commands_helpers.cpp
@@ -132,7 +132,7 @@ namespace {
* sample id for it.
*/
std::vector<AsyncRequestsSender::Request> buildVersionedRequestsForTargetedShards(
- OperationContext* opCtx,
+ boost::intrusive_ptr<ExpressionContext> expCtx,
const NamespaceString& nss,
const CollectionRoutingInfo& cri,
const std::set<ShardId>& shardsToSkip,
@@ -140,6 +140,7 @@ std::vector<AsyncRequestsSender::Request> buildVersionedRequestsForTargetedShard
const BSONObj& query,
const BSONObj& collation,
bool eligibleForSampling = false) {
+ auto opCtx = expCtx->opCtx;
const auto& cm = cri.cm;
@@ -180,7 +181,6 @@ std::vector<AsyncRequestsSender::Request> buildVersionedRequestsForTargetedShard
CollatorFactoryInterface::get(opCtx->getServiceContext())->makeFromBSON(collation));
}
- auto expCtx = make_intrusive<ExpressionContext>(opCtx, std::move(collator), nss);
getShardIdsForQuery(expCtx, query, collation, cm, &shardIds, nullptr /* info */);
const auto targetedSampleId = eligibleForSampling
@@ -422,11 +422,37 @@ std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRouting
Shard::RetryPolicy retryPolicy,
const BSONObj& query,
const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants,
bool eligibleForSampling) {
- const auto requests = buildVersionedRequestsForTargetedShards(
- opCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, collation, eligibleForSampling);
+ auto expCtx = makeExpressionContextWithDefaultsForTargeter(
+ opCtx, nss, collation, boost::none /*explainVerbosity*/, letParameters, runtimeConstants);
+ return scatterGatherVersionedTargetByRoutingTable(expCtx,
+ dbName,
+ nss,
+ cri,
+ cmdObj,
+ readPref,
+ retryPolicy,
+ query,
+ collation,
+ eligibleForSampling);
+}
- return gatherResponses(opCtx, dbName, readPref, retryPolicy, requests);
+[[nodiscard]] std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRoutingTable(
+ boost::intrusive_ptr<ExpressionContext> expCtx,
+ StringData dbName,
+ const NamespaceString& nss,
+ const CollectionRoutingInfo& cri,
+ const BSONObj& cmdObj,
+ const ReadPreferenceSetting& readPref,
+ Shard::RetryPolicy retryPolicy,
+ const BSONObj& query,
+ const BSONObj& collation,
+ bool eligibleForSampling) {
+ const auto requests = buildVersionedRequestsForTargetedShards(
+ expCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, collation, eligibleForSampling);
+ return gatherResponses(expCtx->opCtx, dbName, readPref, retryPolicy, requests);
}
std::vector<AsyncRequestsSender::Response>
@@ -440,9 +466,13 @@ scatterGatherVersionedTargetByRoutingTableNoThrowOnStaleShardVersionErrors(
const ReadPreferenceSetting& readPref,
Shard::RetryPolicy retryPolicy,
const BSONObj& query,
- const BSONObj& collation) {
+ const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants) {
+ auto expCtx = makeExpressionContextWithDefaultsForTargeter(
+ opCtx, nss, collation, boost::none /*explainVerbosity*/, letParameters, runtimeConstants);
const auto requests = buildVersionedRequestsForTargetedShards(
- opCtx, nss, cri, shardsToSkip, cmdObj, query, collation);
+ expCtx, nss, cri, shardsToSkip, cmdObj, query, collation);
return gatherResponsesNoThrowOnStaleShardVersionErrors(
opCtx, dbName, readPref, retryPolicy, requests);
@@ -477,6 +507,12 @@ AsyncRequestsSender::Response executeCommandAgainstShardWithMinKeyChunk(
const BSONObj& cmdObj,
const ReadPreferenceSetting& readPref,
Shard::RetryPolicy retryPolicy) {
+ auto expCtx = makeExpressionContextWithDefaultsForTargeter(opCtx,
+ nss,
+ BSONObj() /*collation*/,
+ boost::none /*explainVerbosity*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
const auto query =
cri.cm.isSharded() ? cri.cm.getShardKeyPattern().getKeyPattern().globalMin() : BSONObj();
@@ -487,7 +523,7 @@ AsyncRequestsSender::Response executeCommandAgainstShardWithMinKeyChunk(
readPref,
retryPolicy,
buildVersionedRequestsForTargetedShards(
- opCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, BSONObj() /* collation */));
+ expCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, BSONObj() /* collation */));
return std::move(responses.front());
}
@@ -670,10 +706,14 @@ std::vector<std::pair<ShardId, BSONObj>> getVersionedRequestsForTargetedShards(
const CollectionRoutingInfo& cri,
const BSONObj& cmdObj,
const BSONObj& query,
- const BSONObj& collation) {
+ const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants) {
+ auto expCtx = makeExpressionContextWithDefaultsForTargeter(
+ opCtx, nss, collation, boost::none /*explainVerbosity*/, letParameters, runtimeConstants);
std::vector<std::pair<ShardId, BSONObj>> requests;
auto ars_requests = buildVersionedRequestsForTargetedShards(
- opCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, collation);
+ expCtx, nss, cri, {} /* shardsToSkip */, cmdObj, query, collation);
std::transform(std::make_move_iterator(ars_requests.begin()),
std::make_move_iterator(ars_requests.end()),
std::back_inserter(requests),
diff --git a/src/mongo/s/cluster_commands_helpers.h b/src/mongo/s/cluster_commands_helpers.h
index 549e91b529c..b69b114025b 100644
--- a/src/mongo/s/cluster_commands_helpers.h
+++ b/src/mongo/s/cluster_commands_helpers.h
@@ -183,8 +183,24 @@ std::vector<AsyncRequestsSender::Response> scatterGatherUnversionedTargetAllShar
Shard::RetryPolicy retryPolicy,
const BSONObj& query,
const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants,
+ bool eligibleForSampling = false);
+/**
+ * This overload is for callers which already have a fully initialized 'ExpressionContext' (e.g.
+ * callers from the aggregation framework). Most callers should prefer the overload above.
+ */
+[[nodiscard]] std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRoutingTable(
+ boost::intrusive_ptr<ExpressionContext> expCtx,
+ StringData dbName,
+ const NamespaceString& nss,
+ const CollectionRoutingInfo& cri,
+ const BSONObj& cmdObj,
+ const ReadPreferenceSetting& readPref,
+ Shard::RetryPolicy retryPolicy,
+ const BSONObj& query,
+ const BSONObj& collation,
bool eligibleForSampling = false);
-
/**
* Utility for dispatching versioned commands on a namespace, deciding which shards to
@@ -205,7 +221,9 @@ scatterGatherVersionedTargetByRoutingTableNoThrowOnStaleShardVersionErrors(
const ReadPreferenceSetting& readPref,
Shard::RetryPolicy retryPolicy,
const BSONObj& query,
- const BSONObj& collation);
+ const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants);
/**
* Utility for dispatching commands against the primary of a database and attaching the appropriate
@@ -297,7 +315,9 @@ std::vector<std::pair<ShardId, BSONObj>> getVersionedRequestsForTargetedShards(
const CollectionRoutingInfo& cri,
const BSONObj& cmdObj,
const BSONObj& query,
- const BSONObj& collation);
+ const BSONObj& collation,
+ const boost::optional<BSONObj>& letParameters,
+ const boost::optional<LegacyRuntimeConstants>& runtimeConstants);
/**
* If the command is running in a transaction, returns the proper routing table to use for targeting
diff --git a/src/mongo/s/commands/cluster_analyze_cmd.cpp b/src/mongo/s/commands/cluster_analyze_cmd.cpp
index ea0ccdb84a7..208d7df1621 100644
--- a/src/mongo/s/commands/cluster_analyze_cmd.cpp
+++ b/src/mongo/s/commands/cluster_analyze_cmd.cpp
@@ -91,8 +91,10 @@ public:
CommandHelpers::filterCommandRequestForPassthrough(unparsedRequest().body)),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
- BSONObj() /* query */,
- BSONObj() /* collation */);
+ BSONObj() /*query*/,
+ BSONObj() /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
for (const auto& shardResult : shardResponses) {
const auto& shardResponse = uassertStatusOK(std::move(shardResult.swResponse));
diff --git a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp
index d830e04415c..2f0d84ed2ad 100644
--- a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp
+++ b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp
@@ -247,8 +247,10 @@ public:
opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObjToSend)),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
- {},
- {});
+ {} /*query*/,
+ {} /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
BSONObjBuilder shardStats;
std::map<std::string, long long> counts;
diff --git a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp
index 6fa1d62d5d7..30e8e904bbd 100644
--- a/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp
+++ b/src/mongo/s/commands/cluster_convert_to_capped_cmd.cpp
@@ -60,8 +60,10 @@ bool nonShardedCollectionCommandPassthrough(OperationContext* opCtx,
cmdObj,
ReadPreferenceSetting::get(opCtx),
retryPolicy,
- {},
- {});
+ {} /*query*/,
+ {} /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
invariant(responses.size() == 1);
const auto cmdResponse = uassertStatusOK(std::move(responses.front().swResponse));
diff --git a/src/mongo/s/commands/cluster_count_cmd.h b/src/mongo/s/commands/cluster_count_cmd.h
index 1325c89a21e..045b1895728 100644
--- a/src/mongo/s/commands/cluster_count_cmd.h
+++ b/src/mongo/s/commands/cluster_count_cmd.h
@@ -152,7 +152,9 @@ public:
Shard::RetryPolicy::kIdempotent,
countRequest.getQuery(),
collation,
- true /* eligibleForSampling */);
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/,
+ true /*eligibleForSampling*/);
} catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) {
// Rewrite the count command as an aggregation.
auto countRequest = CountCommandRequest::parse(IDLParserContext("count"), cmdObj);
@@ -260,7 +262,9 @@ public:
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
targetingQuery,
- targetingCollation);
+ targetingCollation,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
} catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) {
CountCommandRequest countRequest(NamespaceStringOrUUID(NamespaceString{}));
try {
diff --git a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp
index e07aa1700e0..095ccd6bbe9 100644
--- a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp
+++ b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp
@@ -121,8 +121,10 @@ public:
applyReadWriteConcern(opCtx, this, cmdToBeSent)),
ReadPreferenceSetting(ReadPreference::PrimaryOnly),
Shard::RetryPolicy::kNoRetry,
- BSONObj() /* query */,
- BSONObj() /* collation */);
+ BSONObj() /*query*/,
+ BSONObj() /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
std::string errmsg;
const bool ok =
diff --git a/src/mongo/s/commands/cluster_data_size_cmd.cpp b/src/mongo/s/commands/cluster_data_size_cmd.cpp
index dda5ed02fcf..057f9e8ad73 100644
--- a/src/mongo/s/commands/cluster_data_size_cmd.cpp
+++ b/src/mongo/s/commands/cluster_data_size_cmd.cpp
@@ -88,8 +88,10 @@ public:
CommandHelpers::filterCommandRequestForPassthrough(cmd.toBSON({}))),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
- {},
- {});
+ {} /*query*/,
+ {} /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
std::int64_t size = 0;
std::int64_t numObjects = 0;
diff --git a/src/mongo/s/commands/cluster_distinct_cmd.cpp b/src/mongo/s/commands/cluster_distinct_cmd.cpp
index 3c9ff302f7a..5fb9a701419 100644
--- a/src/mongo/s/commands/cluster_distinct_cmd.cpp
+++ b/src/mongo/s/commands/cluster_distinct_cmd.cpp
@@ -146,7 +146,9 @@ public:
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
targetingQuery,
- targetingCollation);
+ targetingCollation,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
} catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) {
auto parsedDistinct = ParsedDistinct::parse(
opCtx, ex->getNamespace(), cmdObj, ExtensionsCallbackNoop(), true);
@@ -234,6 +236,8 @@ public:
Shard::RetryPolicy::kIdempotent,
query,
collation,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/,
true /* eligibleForSampling */);
} catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& ex) {
auto parsedDistinct = ParsedDistinct::parse(
diff --git a/src/mongo/s/commands/cluster_filemd5_cmd.cpp b/src/mongo/s/commands/cluster_filemd5_cmd.cpp
index 63b5a2a5033..12ab9f07730 100644
--- a/src/mongo/s/commands/cluster_filemd5_cmd.cpp
+++ b/src/mongo/s/commands/cluster_filemd5_cmd.cpp
@@ -107,7 +107,9 @@ public:
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
routingQuery,
- CollationSpec::kSimpleSpec);
+ CollationSpec::kSimpleSpec,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
invariant(shardResults.size() == 1);
const auto shardResponse = uassertStatusOK(std::move(shardResults[0].swResponse));
uassertStatusOK(shardResponse.status);
diff --git a/src/mongo/s/commands/cluster_find_cmd.h b/src/mongo/s/commands/cluster_find_cmd.h
index e8ed843575a..cd46d911895 100644
--- a/src/mongo/s/commands/cluster_find_cmd.h
+++ b/src/mongo/s/commands/cluster_find_cmd.h
@@ -161,7 +161,9 @@ public:
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
findCommand->getFilter(),
- findCommand->getCollation());
+ findCommand->getCollation(),
+ findCommand->getLet(),
+ findCommand->getLegacyRuntimeConstants());
millisElapsed = timer.millis();
const char* mongosStageName =
diff --git a/src/mongo/s/commands/cluster_index_filter_cmd.cpp b/src/mongo/s/commands/cluster_index_filter_cmd.cpp
index f2a1bf18dba..cd81e568d77 100644
--- a/src/mongo/s/commands/cluster_index_filter_cmd.cpp
+++ b/src/mongo/s/commands/cluster_index_filter_cmd.cpp
@@ -101,7 +101,9 @@ public:
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
query,
- CollationSpec::kSimpleSpec);
+ CollationSpec::kSimpleSpec,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
// Sort shard responses by shard id.
std::sort(shardResponses.begin(),
diff --git a/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp
index b1e9ff01062..5e75487858c 100644
--- a/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp
+++ b/src/mongo/s/commands/cluster_plan_cache_clear_cmd.cpp
@@ -105,7 +105,9 @@ bool ClusterPlanCacheClearCmd::run(OperationContext* opCtx,
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
query,
- CollationSpec::kSimpleSpec);
+ CollationSpec::kSimpleSpec,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
// Sort shard responses by shard id.
std::sort(shardResponses.begin(),
diff --git a/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp b/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp
index 3cd1e398325..e60c92d29d8 100644
--- a/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp
+++ b/src/mongo/s/commands/cluster_set_index_commit_quorum_cmd.cpp
@@ -116,8 +116,10 @@ public:
opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kNotIdempotent,
- BSONObj() /* query */,
- BSONObj() /* collation */);
+ BSONObj() /*query*/,
+ BSONObj() /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
std::string errmsg;
const bool ok =
diff --git a/src/mongo/s/commands/cluster_validate_cmd.cpp b/src/mongo/s/commands/cluster_validate_cmd.cpp
index 3d9e62e8e45..36512d0c920 100644
--- a/src/mongo/s/commands/cluster_validate_cmd.cpp
+++ b/src/mongo/s/commands/cluster_validate_cmd.cpp
@@ -91,8 +91,10 @@ public:
opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
ReadPreferenceSetting::get(opCtx),
Shard::RetryPolicy::kIdempotent,
- {},
- {});
+ {} /*query*/,
+ {} /*collation*/,
+ boost::none /*letParameters*/,
+ boost::none /*runtimeConstants*/);
Status firstFailedShardStatus = Status::OK();
bool isValid = true;