summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/variables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/variables.cpp')
-rw-r--r--src/mongo/db/pipeline/variables.cpp28
1 files changed, 23 insertions, 5 deletions
diff --git a/src/mongo/db/pipeline/variables.cpp b/src/mongo/db/pipeline/variables.cpp
index 26793962efd..279b8630ce6 100644
--- a/src/mongo/db/pipeline/variables.cpp
+++ b/src/mongo/db/pipeline/variables.cpp
@@ -40,6 +40,21 @@
namespace mongo {
+namespace {
+
+// We need to be careful when serializing values, e.g. to populate the 'let' parameter of a command
+// to be sent over the wire. First, missing values should be serialied as $$REMOVE, otherwise they
+// might be incorrectly omitted or serialized as empty objects ({}). Also, we should wrap values in
+// $literal to avoid a scenario like the following: suppose we had a user-defined 'let' specified as
+// {let: {a: {$literal: "$notAFieldName"}}}. On mongos, this will be evaluated to the string
+// "$notAFieldName". When we serialize it again for the shard commands, it must appear as {$literal:
+// "$notAFieldName"}, not simply "$notAFieldName", since the latter will be treated as a field name
+// by mongods.
+Value serializeValue(Value val) {
+ return val.missing() ? Value("$$REMOVE"_sd) : Value(DOC("$literal" << val));
+}
+} // namespace
+
using namespace std::string_literals;
constexpr Variables::Id Variables::kRootId;
@@ -330,7 +345,8 @@ LegacyRuntimeConstants Variables::transitionalExtractRuntimeConstants() const {
}
Variables::Id VariablesParseState::defineVariable(StringData name) {
- // Caller should have validated before hand by using variableValidationvalidateNameForUserWrite.
+ // Caller should have validated before hand by using
+ // variableValidation::validateNameForUserWrite.
massert(17275,
"Can't redefine a non-user-writable variable",
Variables::kBuiltinVarNameToId.find(name) == Variables::kBuiltinVarNameToId.end());
@@ -374,8 +390,9 @@ std::set<Variables::Id> VariablesParseState::getDefinedVariableIDs() const {
BSONObj VariablesParseState::serialize(const Variables& vars) const {
auto bob = BSONObjBuilder{};
for (auto&& [var_name, id] : _variables)
- if (vars.hasValue(id))
- bob << var_name << Value(DOC("$literal" << vars.getValue(id)));
+ if (vars.hasValue(id)) {
+ bob << var_name << serializeValue(vars.getValue(id));
+ }
// System variables have to be added separately since the variable IDs are reserved and not
// allocated like normal variables, and so not present in '_variables'.
@@ -387,8 +404,9 @@ std::pair<LegacyRuntimeConstants, BSONObj> VariablesParseState::transitionalComp
const Variables& vars) const {
auto bob = BSONObjBuilder{};
for (auto&& [var_name, id] : _variables)
- if (vars.hasValue(id))
- bob << var_name << Value(DOC("$literal" << vars.getValue(id)));
+ if (vars.hasValue(id)) {
+ bob << var_name << serializeValue(vars.getValue(id));
+ }
return {vars.transitionalExtractRuntimeConstants(), bob.obj()};
}