diff options
Diffstat (limited to 'src/mongo/db/pipeline/variables.cpp')
| -rw-r--r-- | src/mongo/db/pipeline/variables.cpp | 28 |
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()}; } |
