diff options
author | Ted Tuckman <ted.tuckman@mongodb.com> | 2020-08-19 10:04:10 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-26 12:52:51 +0000 |
commit | 199df5ec6c6b8c0fc8e74dfad8a074547b79d3f2 (patch) | |
tree | cd86a8fb93148a0bcc221313681c58e52031661d /src/mongo/db/pipeline | |
parent | 4dc5ad1c019849f2084bb9d30419d303679e6afe (diff) | |
download | mongo-199df5ec6c6b8c0fc8e74dfad8a074547b79d3f2.tar.gz |
SERVER-49927 Add $FieldPath to grammar
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r-- | src/mongo/db/pipeline/SConscript | 10 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_graph_lookup_test.cpp | 224 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_group.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_lookup.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_merge.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.h | 12 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_field_path_test.cpp | 56 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_nary_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_object_test.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variable_validation.cpp | 82 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variable_validation.h | 40 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variables.cpp | 53 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variables.h | 7 |
15 files changed, 342 insertions, 223 deletions
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index 31e47662a07..887fb93486b 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -55,6 +55,15 @@ env.Library( ) env.Library( + target='variable_validation', + source=[ + "variable_validation.cpp", + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ] +) +env.Library( target='expression_context', source=[ 'expression.cpp', @@ -80,6 +89,7 @@ env.Library( '$BUILD_DIR/mongo/util/summation', 'aggregation_request', 'dependencies', + 'variable_validation', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/vector_clock', diff --git a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp index 5d4fe741a6c..c59ed9c2ea4 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp @@ -87,17 +87,17 @@ TEST_F(DocumentSourceGraphLookUpTest, expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "_id"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "_id"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); ASSERT_THROWS_CODE(graphLookupStage->getNext(), AssertionException, 40271); } @@ -116,17 +116,17 @@ TEST_F(DocumentSourceGraphLookUpTest, expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "_id"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "_id"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); ASSERT_THROWS_CODE(graphLookupStage->getNext(), AssertionException, 40271); @@ -146,17 +146,17 @@ TEST_F(DocumentSourceGraphLookUpTest, {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); auto unwindStage = DocumentSourceUnwind::create(expCtx, "results", false, boost::none); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "_id"), - boost::none, - boost::none, - boost::none, - unwindStage); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "_id"), + boost::none, + boost::none, + boost::none, + unwindStage); graphLookupStage->setSource(inputMock.get()); ASSERT_THROWS_CODE(graphLookupStage->getNext(), AssertionException, 40271); @@ -189,17 +189,17 @@ TEST_F(DocumentSourceGraphLookUpTest, expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "_id"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "_id"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); graphLookupStage->setSource(inputMock.get()); @@ -253,17 +253,17 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldPropagatePauses) { expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "startPoint"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startPoint"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); @@ -329,17 +329,17 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldPropagatePausesWhileUnwinding) { auto unwindStage = DocumentSourceUnwind::create( expCtx, "results", preserveNullAndEmptyArrays, includeArrayIndex); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "startPoint"), - boost::none, - boost::none, - boost::none, - unwindStage); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startPoint"), + boost::none, + boost::none, + boost::none, + unwindStage); graphLookupStage->setSource(inputMock.get()); @@ -388,17 +388,17 @@ TEST_F(DocumentSourceGraphLookUpTest, GraphLookupShouldReportAsFieldIsModified) {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{}); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "startPoint"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startPoint"), + boost::none, + boost::none, + boost::none, + boost::none); auto modifiedPaths = graphLookupStage->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kFiniteSet); @@ -415,17 +415,17 @@ TEST_F(DocumentSourceGraphLookUpTest, GraphLookupShouldReportFieldsModifiedByAbs std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{}); auto unwindStage = DocumentSourceUnwind::create(expCtx, "results", false, std::string("arrIndex")); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "from", - "to", - ExpressionFieldPath::create(expCtx.get(), "startPoint"), - boost::none, - boost::none, - boost::none, - unwindStage); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "from", + "to", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startPoint"), + boost::none, + boost::none, + boost::none, + unwindStage); auto modifiedPaths = graphLookupStage->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kFiniteSet); @@ -455,8 +455,8 @@ TEST_F(DocumentSourceGraphLookUpTest, GraphLookupWithComparisonExpressionForStar "to", ExpressionCompare::create(expCtx.get(), ExpressionCompare::GT, - ExpressionFieldPath::create(expCtx.get(), "a"), - ExpressionFieldPath::create(expCtx.get(), "b")), + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "a"), + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "b")), boost::none, boost::none, boost::none, @@ -510,17 +510,17 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldExpandArraysAtEndOfConnectFromField) expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "to", - "_id", - ExpressionFieldPath::create(expCtx.get(), "startVal"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "to", + "_id", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startVal"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); graphLookupStage->setSource(inputMock.get()); @@ -583,17 +583,17 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldNotExpandArraysWithinArraysAtEndOfCo expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}}); expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(std::move(fromContents)); - auto graphLookupStage = - DocumentSourceGraphLookUp::create(expCtx, - fromNs, - "results", - "connectedTo", - "coordinate", - ExpressionFieldPath::create(expCtx.get(), "startVal"), - boost::none, - boost::none, - boost::none, - boost::none); + auto graphLookupStage = DocumentSourceGraphLookUp::create( + expCtx, + fromNs, + "results", + "connectedTo", + "coordinate", + ExpressionFieldPath::deprecatedCreate(expCtx.get(), "startVal"), + boost::none, + boost::none, + boost::none, + boost::none); graphLookupStage->setSource(inputMock.get()); graphLookupStage->setSource(inputMock.get()); diff --git a/src/mongo/db/pipeline/document_source_group.cpp b/src/mongo/db/pipeline/document_source_group.cpp index cf31fd10c6e..d53ca4fb3cf 100644 --- a/src/mongo/db/pipeline/document_source_group.cpp +++ b/src/mongo/db/pipeline/document_source_group.cpp @@ -826,7 +826,7 @@ DocumentSourceGroup::rewriteGroupAsTransformOnFirstDocument() const { // The _id field can be specified either as a fieldpath (ex. _id: "$a") or as a singleton // object (ex. _id: {v: "$a"}). if (_idFieldNames.empty()) { - idField = ExpressionFieldPath::create(pExpCtx.get(), groupId); + idField = ExpressionFieldPath::deprecatedCreate(pExpCtx.get(), groupId); } else { invariant(_idFieldNames.size() == 1); idField = ExpressionObject::create(pExpCtx.get(), diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 25fe9668ce0..94a4071d4ad 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -42,6 +42,7 @@ #include "mongo/db/pipeline/document_source_merge_gen.h" #include "mongo/db/pipeline/expression.h" #include "mongo/db/pipeline/expression_context.h" +#include "mongo/db/pipeline/variable_validation.h" #include "mongo/db/query/query_knobs_gen.h" #include "mongo/platform/overflow_arithmetic.h" #include "mongo/util/fail_point.h" @@ -158,7 +159,7 @@ DocumentSourceLookUp::DocumentSourceLookUp(NamespaceString fromNs, for (auto&& varElem : letVariables) { const auto varName = varElem.fieldNameStringData(); - Variables::validateNameForUserWrite(varName); + variableValidation::validateNameForUserWrite(varName); _letVariables.emplace_back( varName.toString(), diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp index 2dd399d6fce..2b8223d8753 100644 --- a/src/mongo/db/pipeline/document_source_merge.cpp +++ b/src/mongo/db/pipeline/document_source_merge.cpp @@ -40,6 +40,7 @@ #include "mongo/db/curop_failpoint_helpers.h" #include "mongo/db/ops/write_ops.h" #include "mongo/db/pipeline/document_path_support.h" +#include "mongo/db/pipeline/variable_validation.h" #include "mongo/logv2/log.h" namespace mongo { @@ -370,7 +371,7 @@ DocumentSourceMerge::DocumentSourceMerge(NamespaceString outputNs, for (auto&& varElem : *letVariables) { const auto varName = varElem.fieldNameStringData(); - Variables::validateNameForUserWrite(varName); + variableValidation::validateNameForUserWrite(varName); _letVariables->emplace( varName.toString(), diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 71d24d13528..c6c0823eee7 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -45,6 +45,7 @@ #include "mongo/db/hasher.h" #include "mongo/db/jsobj.h" #include "mongo/db/pipeline/expression_context.h" +#include "mongo/db/pipeline/variable_validation.h" #include "mongo/db/query/datetime/date_time_support.h" #include "mongo/platform/bits.h" #include "mongo/platform/decimal128.h" @@ -2045,8 +2046,8 @@ Expression::ComputedPaths ExpressionObject::getComputedPaths(const std::string& /* --------------------- ExpressionFieldPath --------------------------- */ // this is the old deprecated version only used by tests not using variables -intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::create(ExpressionContext* const expCtx, - const string& fieldPath) { +intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::deprecatedCreate( + ExpressionContext* const expCtx, const string& fieldPath) { return new ExpressionFieldPath(expCtx, "CURRENT." + fieldPath, Variables::kRootId); } @@ -2066,7 +2067,7 @@ intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::parse(ExpressionContext* const StringData rawSD = raw; const StringData fieldPath = rawSD.substr(2); // strip off $$ const StringData varName = fieldPath.substr(0, fieldPath.find('.')); - Variables::validateNameForUserRead(varName); + variableValidation::validateNameForUserRead(varName); auto varId = vps.getVariable(varName); return new ExpressionFieldPath(expCtx, fieldPath.toString(), varId); } else { @@ -2076,6 +2077,18 @@ intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::parse(ExpressionContext* } } +intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::createPathFromString( + ExpressionContext* const expCtx, const string& raw, const VariablesParseState& vps) { + return new ExpressionFieldPath(expCtx, "CURRENT." + raw, vps.getVariable("CURRENT")); +} +intrusive_ptr<ExpressionFieldPath> ExpressionFieldPath::createVarFromString( + ExpressionContext* const expCtx, const string& raw, const VariablesParseState& vps) { + const auto rawSD = StringData{raw}; + const StringData varName = rawSD.substr(0, rawSD.find('.')); + auto varId = vps.getVariable(varName); + return new ExpressionFieldPath(expCtx, raw, varId); +} + ExpressionFieldPath::ExpressionFieldPath(ExpressionContext* const expCtx, const string& theFieldPath, Variables::Id variable) @@ -2249,7 +2262,7 @@ intrusive_ptr<Expression> ExpressionFilter::parse(ExpressionContext* const expCt // If "as" is not specified, then use "this" by default. auto varName = asElem.eoo() ? "this" : asElem.str(); - Variables::validateNameForUserWrite(varName); + variableValidation::validateNameForUserWrite(varName); Variables::Id varId = vpsSub.defineVariable(varName); // Parse "cond", has access to "as" variable. @@ -2379,7 +2392,7 @@ intrusive_ptr<Expression> ExpressionLet::parse(ExpressionContext* const expCtx, std::vector<Variables::Id> orderedVariableIds; for (auto&& varElem : varsObj) { const string varName = varElem.fieldName(); - Variables::validateNameForUserWrite(varName); + variableValidation::validateNameForUserWrite(varName); Variables::Id id = vpsSub.defineVariable(varName); orderedVariableIds.push_back(id); @@ -2491,7 +2504,7 @@ intrusive_ptr<Expression> ExpressionMap::parse(ExpressionContext* const expCtx, // If "as" is not specified, then use "this" by default. auto varName = asElem.eoo() ? "this" : asElem.str(); - Variables::validateNameForUserWrite(varName); + variableValidation::validateNameForUserWrite(varName); Variables::Id varId = vpsSub.defineVariable(varName); // parse "in" diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h index a21f4c8bd39..fc6f16c0eb8 100644 --- a/src/mongo/db/pipeline/expression.h +++ b/src/mongo/db/pipeline/expression.h @@ -1384,13 +1384,19 @@ public: indicator @returns the newly created field path expression */ - static boost::intrusive_ptr<ExpressionFieldPath> create(ExpressionContext* const expCtx, - const std::string& fieldPath); + static boost::intrusive_ptr<ExpressionFieldPath> deprecatedCreate( + ExpressionContext* const expCtx, const std::string& fieldPath); - /// Like create(), but works with the raw std::string from the user with the "$" prefixes. + // Parse from the raw std::string from the user with the "$" prefixes. static boost::intrusive_ptr<ExpressionFieldPath> parse(ExpressionContext* const expCtx, const std::string& raw, const VariablesParseState& vps); + // Create from a non-prefixed string. Assumes path not variable. + static boost::intrusive_ptr<ExpressionFieldPath> createPathFromString( + ExpressionContext* const expCtx, const std::string& raw, const VariablesParseState& vps); + // Create from a non-prefixed string. Assumes variable not path. + static boost::intrusive_ptr<ExpressionFieldPath> createVarFromString( + ExpressionContext* const expCtx, const std::string& raw, const VariablesParseState& vps); /** * Returns true if this expression logically represents the path 'dottedPath'. For example, if diff --git a/src/mongo/db/pipeline/expression_field_path_test.cpp b/src/mongo/db/pipeline/expression_field_path_test.cpp index 14064134b9d..9fa73620dfe 100644 --- a/src/mongo/db/pipeline/expression_field_path_test.cpp +++ b/src/mongo/db/pipeline/expression_field_path_test.cpp @@ -68,7 +68,7 @@ class Invalid { public: void run() { auto expCtx = ExpressionContextForTest{}; - ASSERT_THROWS(ExpressionFieldPath::create(&expCtx, ""), AssertionException); + ASSERT_THROWS(ExpressionFieldPath::deprecatedCreate(&expCtx, ""), AssertionException); } }; @@ -104,7 +104,7 @@ TEST(FieldPath, RemoveOptimizesToMissingValue) { TEST(FieldPath, NoOptimizationOnNormalPath) { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a"); + intrusive_ptr<Expression> expression = ExpressionFieldPath::deprecatedCreate(&expCtx, "a"); // An attempt to optimize returns the Expression itself. ASSERT_EQUALS(expression, expression->optimize()); } @@ -205,7 +205,8 @@ class Dependencies { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); DepsTracker dependencies; expression->addDependencies(&dependencies); ASSERT_EQUALS(1U, dependencies.fields.size()); @@ -220,7 +221,7 @@ class Missing { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a"); + intrusive_ptr<Expression> expression = ExpressionFieldPath::deprecatedCreate(&expCtx, "a"); ASSERT_BSONOBJ_BINARY_EQ(fromjson("{}"), toBson(expression->evaluate({}, &expCtx.variables))); } @@ -231,7 +232,7 @@ class Present { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a"); + intrusive_ptr<Expression> expression = ExpressionFieldPath::deprecatedCreate(&expCtx, "a"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':123}"), toBson(expression->evaluate(fromBson(BSON("a" << 123)), &expCtx.variables))); @@ -243,7 +244,8 @@ class NestedBelowNull { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{}"), toBson(expression->evaluate(fromBson(fromjson("{a:null}")), &expCtx.variables))); @@ -255,7 +257,8 @@ class NestedBelowUndefined { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{}"), toBson(expression->evaluate(fromBson(fromjson("{a:undefined}")), &expCtx.variables))); @@ -267,7 +270,8 @@ class NestedBelowMissing { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{}"), toBson(expression->evaluate(fromBson(fromjson("{z:1}")), &expCtx.variables))); @@ -279,7 +283,8 @@ class NestedBelowInt { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{}"), toBson(expression->evaluate(fromBson(BSON("a" << 2)), &expCtx.variables))); @@ -291,7 +296,8 @@ class NestedValue { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ(BSON("" << 55), toBson(expression->evaluate(fromBson(BSON("a" << BSON("b" << 55))), &expCtx.variables))); @@ -303,7 +309,8 @@ class NestedBelowEmptyObject { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{}"), toBson(expression->evaluate(fromBson(BSON("a" << BSONObj())), &expCtx.variables))); @@ -315,7 +322,8 @@ class NestedBelowEmptyArray { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( BSON("" << BSONArray()), toBson(expression->evaluate(fromBson(BSON("a" << BSONArray())), &expCtx.variables))); @@ -327,7 +335,8 @@ class NestedBelowArrayWithNull { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[]}"), toBson(expression->evaluate(fromBson(fromjson("{a:[null]}")), &expCtx.variables))); @@ -339,7 +348,8 @@ class NestedBelowArrayWithUndefined { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[]}"), toBson(expression->evaluate(fromBson(fromjson("{a:[undefined]}")), &expCtx.variables))); @@ -351,7 +361,8 @@ class NestedBelowArrayWithInt { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[]}"), toBson(expression->evaluate(fromBson(fromjson("{a:[1]}")), &expCtx.variables))); @@ -363,7 +374,8 @@ class NestedWithinArray { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[9]}"), toBson(expression->evaluate(fromBson(fromjson("{a:[{b:9}]}")), &expCtx.variables))); @@ -375,7 +387,8 @@ class MultipleArrayValues { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[9,20]}"), toBson(expression->evaluate( @@ -389,7 +402,8 @@ class ExpandNestedArrays { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b.c"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b.c"); ASSERT_BSONOBJ_BINARY_EQ( fromjson("{'':[[1,2],3,[4],[[5]],[6,7]]}"), toBson(expression->evaluate(fromBson(fromjson("{a:[{b:[{c:1},{c:2}]}," @@ -406,7 +420,8 @@ class AddToBsonObj { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b.c"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b.c"); ASSERT_BSONOBJ_BINARY_EQ(BSON("foo" << "$a.b.c"), BSON("foo" << expression->serialize(false))); @@ -418,7 +433,8 @@ class AddToBsonArray { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionFieldPath::create(&expCtx, "a.b.c"); + intrusive_ptr<Expression> expression = + ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b.c"); BSONArrayBuilder bab; bab << expression->serialize(false); ASSERT_BSONOBJ_BINARY_EQ(BSON_ARRAY("$a.b.c"), bab.arr()); diff --git a/src/mongo/db/pipeline/expression_nary_test.cpp b/src/mongo/db/pipeline/expression_nary_test.cpp index 3b709c4c7ae..3d284235335 100644 --- a/src/mongo/db/pipeline/expression_nary_test.cpp +++ b/src/mongo/db/pipeline/expression_nary_test.cpp @@ -208,7 +208,8 @@ TEST_F(ExpressionNaryTest, AddedConstantOperandIsSerialized) { } TEST_F(ExpressionNaryTest, AddedFieldPathOperandIsSerialized) { - _notAssociativeNorCommutative->addOperand(ExpressionFieldPath::create(&expCtx, "ab.c")); + _notAssociativeNorCommutative->addOperand( + ExpressionFieldPath::deprecatedCreate(&expCtx, "ab.c")); assertContents(_notAssociativeNorCommutative, BSON_ARRAY("$ab.c")); } @@ -222,7 +223,8 @@ TEST_F(ExpressionNaryTest, ValidateConstantExpressionDependency) { } TEST_F(ExpressionNaryTest, ValidateFieldPathExpressionDependency) { - _notAssociativeNorCommutative->addOperand(ExpressionFieldPath::create(&expCtx, "ab.c")); + _notAssociativeNorCommutative->addOperand( + ExpressionFieldPath::deprecatedCreate(&expCtx, "ab.c")); assertDependencies(_notAssociativeNorCommutative, BSON_ARRAY("ab.c")); } diff --git a/src/mongo/db/pipeline/expression_object_test.cpp b/src/mongo/db/pipeline/expression_object_test.cpp index 5b339bf911b..7246e9569e3 100644 --- a/src/mongo/db/pipeline/expression_object_test.cpp +++ b/src/mongo/db/pipeline/expression_object_test.cpp @@ -211,10 +211,11 @@ TEST(ExpressionObjectEvaluate, ShouldEvaluateEachField) { TEST(ExpressionObjectEvaluate, OrderOfFieldsInOutputShouldMatchOrderInSpecification) { auto expCtx = ExpressionContextForTest{}; - auto object = ExpressionObject::create(&expCtx, - {{"a", ExpressionFieldPath::create(&expCtx, "a")}, - {"b", ExpressionFieldPath::create(&expCtx, "b")}, - {"c", ExpressionFieldPath::create(&expCtx, "c")}}); + auto object = + ExpressionObject::create(&expCtx, + {{"a", ExpressionFieldPath::deprecatedCreate(&expCtx, "a")}, + {"b", ExpressionFieldPath::deprecatedCreate(&expCtx, "b")}, + {"c", ExpressionFieldPath::deprecatedCreate(&expCtx, "c")}}); ASSERT_VALUE_EQ( Value(Document{{"a", "A"_sd}, {"b", "B"_sd}, {"c", "C"_sd}}), object->evaluate(Document{{"c", "C"_sd}, {"a", "A"_sd}, {"b", "B"_sd}, {"_id", "ID"_sd}}, @@ -223,10 +224,10 @@ TEST(ExpressionObjectEvaluate, OrderOfFieldsInOutputShouldMatchOrderInSpecificat TEST(ExpressionObjectEvaluate, ShouldRemoveFieldsThatHaveMissingValues) { auto expCtx = ExpressionContextForTest{}; - auto object = - ExpressionObject::create(&expCtx, - {{"a", ExpressionFieldPath::create(&expCtx, "a.b")}, - {"b", ExpressionFieldPath::create(&expCtx, "missing")}}); + auto object = ExpressionObject::create( + &expCtx, + {{"a", ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b")}, + {"b", ExpressionFieldPath::deprecatedCreate(&expCtx, "missing")}}); ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document(), &(expCtx.variables))); ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document{{"a", 1}}, &(expCtx.variables))); } @@ -236,9 +237,10 @@ TEST(ExpressionObjectEvaluate, ShouldEvaluateFieldsWithinNestedObject) { auto object = ExpressionObject::create( &expCtx, {{"a", - ExpressionObject::create(&expCtx, - {{"b", ExpressionConstant::create(&expCtx, Value{1})}, - {"c", ExpressionFieldPath::create(&expCtx, "_id")}})}}); + ExpressionObject::create( + &expCtx, + {{"b", ExpressionConstant::create(&expCtx, Value{1})}, + {"c", ExpressionFieldPath::deprecatedCreate(&expCtx, "_id")}})}}); ASSERT_VALUE_EQ(Value(Document{{"a", Document{{"b", 1}}}}), object->evaluate(Document(), &(expCtx.variables))); ASSERT_VALUE_EQ(Value(Document{{"a", Document{{"b", 1}, {"c", "ID"_sd}}}}), @@ -247,8 +249,8 @@ TEST(ExpressionObjectEvaluate, ShouldEvaluateFieldsWithinNestedObject) { TEST(ExpressionObjectEvaluate, ShouldEvaluateToEmptyDocumentIfAllFieldsAreMissing) { auto expCtx = ExpressionContextForTest{}; - auto object = - ExpressionObject::create(&expCtx, {{"a", ExpressionFieldPath::create(&expCtx, "missing")}}); + auto object = ExpressionObject::create( + &expCtx, {{"a", ExpressionFieldPath::deprecatedCreate(&expCtx, "missing")}}); ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document(), &(expCtx.variables))); auto objectWithNestedObject = ExpressionObject::create(&expCtx, {{"nested", object}}); @@ -271,8 +273,8 @@ TEST(ExpressionObjectDependencies, ConstantValuesShouldNotBeAddedToDependencies) TEST(ExpressionObjectDependencies, FieldPathsShouldBeAddedToDependencies) { auto expCtx = ExpressionContextForTest{}; - auto object = - ExpressionObject::create(&expCtx, {{"x", ExpressionFieldPath::create(&expCtx, "c.d")}}); + auto object = ExpressionObject::create( + &expCtx, {{"x", ExpressionFieldPath::deprecatedCreate(&expCtx, "c.d")}}); DepsTracker deps; object->addDependencies(&deps); ASSERT_EQ(deps.fields.size(), 1UL); diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 5288fe96c00..e1eeb44d3d2 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -548,7 +548,7 @@ class Dependencies { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> nested = ExpressionFieldPath::create(&expCtx, "a.b"); + intrusive_ptr<Expression> nested = ExpressionFieldPath::deprecatedCreate(&expCtx, "a.b"); intrusive_ptr<Expression> expression = ExpressionCoerceToBool::create(&expCtx, nested); DepsTracker dependencies; expression->addDependencies(&dependencies); @@ -564,8 +564,8 @@ class AddToBsonObj { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = - ExpressionCoerceToBool::create(&expCtx, ExpressionFieldPath::create(&expCtx, "foo")); + intrusive_ptr<Expression> expression = ExpressionCoerceToBool::create( + &expCtx, ExpressionFieldPath::deprecatedCreate(&expCtx, "foo")); // serialized as $and because CoerceToBool isn't an ExpressionNary ASSERT_BSONOBJ_BINARY_EQ(fromjson("{field:{$and:['$foo']}}"), toBsonObj(expression)); @@ -582,8 +582,8 @@ class AddToBsonArray { public: void run() { auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = - ExpressionCoerceToBool::create(&expCtx, ExpressionFieldPath::create(&expCtx, "foo")); + intrusive_ptr<Expression> expression = ExpressionCoerceToBool::create( + &expCtx, ExpressionFieldPath::deprecatedCreate(&expCtx, "foo")); // serialized as $and because CoerceToBool isn't an ExpressionNary ASSERT_BSONOBJ_BINARY_EQ(BSON_ARRAY(fromjson("{$and:['$foo']}")), toBsonArray(expression)); diff --git a/src/mongo/db/pipeline/variable_validation.cpp b/src/mongo/db/pipeline/variable_validation.cpp new file mode 100644 index 00000000000..a0b29b2f59e --- /dev/null +++ b/src/mongo/db/pipeline/variable_validation.cpp @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2020-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. + */ + +#include "mongo/base/error_codes.h" +#include "mongo/util/str.h" + +namespace mongo::variableValidation { +void validateName(StringData varName, + std::function<bool(char)> prefixPred, + std::function<bool(char)> suffixPred, + int prefixLen) { + uassert(16866, "empty variable names are not allowed", !varName.empty()); + for (int i = 0; i < prefixLen; ++i) + if (!prefixPred(varName[i])) + uasserted(16867, + str::stream() + << "'" << varName + << "' starts with an invalid character for a user variable name"); + + for (size_t i = prefixLen; i < varName.size(); i++) + if (!suffixPred(varName[i])) + uasserted(16868, + str::stream() << "'" << varName << "' contains an invalid character " + << "for a variable name: '" << varName[i] << "'"); +} + +void validateNameForUserWrite(StringData varName) { + // System variables users allowed to write to (currently just one) + if (varName == "CURRENT") { + return; + } + validateName(varName, + [](char ch) -> bool { + return (ch >= 'a' && ch <= 'z') || (ch & '\x80'); // non-ascii + }, + [](char ch) -> bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || (ch == '_') || (ch & '\x80'); // non-ascii + }, + 1); +} + +void validateNameForUserRead(StringData varName) { + validateName(varName, + [](char ch) -> bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + (ch & '\x80'); // non-ascii + }, + [](char ch) -> bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || (ch == '_') || (ch & '\x80'); // non-ascii + }, + 1); +} + +} // namespace mongo::variableValidation diff --git a/src/mongo/db/pipeline/variable_validation.h b/src/mongo/db/pipeline/variable_validation.h new file mode 100644 index 00000000000..a11b1df49cd --- /dev/null +++ b/src/mongo/db/pipeline/variable_validation.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2020-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 + + +namespace mongo::variableValidation { +void validateNameForUserWrite(StringData varName); +void validateNameForUserRead(StringData varName); +void validateName(StringData varName, + std::function<bool(char)> prefixPred, + std::function<bool(char)> suffixPred, + int prefixLen); +} // namespace mongo::variableValidation diff --git a/src/mongo/db/pipeline/variables.cpp b/src/mongo/db/pipeline/variables.cpp index 485569152d1..28d8e135271 100644 --- a/src/mongo/db/pipeline/variables.cpp +++ b/src/mongo/db/pipeline/variables.cpp @@ -32,6 +32,7 @@ #include "mongo/db/client.h" #include "mongo/db/logical_clock.h" #include "mongo/db/pipeline/expression.h" +#include "mongo/db/pipeline/variable_validation.h" #include "mongo/platform/basic.h" #include "mongo/platform/random.h" #include "mongo/util/str.h" @@ -88,54 +89,6 @@ const std::map<StringData, std::function<void(const Value&)>> Variables::kSystem value.getType() == BSONType::Bool); }}}; -void Variables::validateName(StringData varName, - std::function<bool(char)> prefixPred, - std::function<bool(char)> suffixPred, - int prefixLen) { - uassert(16866, "empty variable names are not allowed", !varName.empty()); - for (int i = 0; i < prefixLen; ++i) - if (!prefixPred(varName[i])) - uasserted(16867, - str::stream() - << "'" << varName - << "' starts with an invalid character for a user variable name"); - - for (size_t i = prefixLen; i < varName.size(); i++) - if (!suffixPred(varName[i])) - uasserted(16868, - str::stream() << "'" << varName << "' contains an invalid character " - << "for a variable name: '" << varName[i] << "'"); -} - -void Variables::validateNameForUserWrite(StringData varName) { - // System variables users allowed to write to (currently just one) - if (varName == "CURRENT") { - return; - } - validateName(varName, - [](char ch) -> bool { - return (ch >= 'a' && ch <= 'z') || (ch & '\x80'); // non-ascii - }, - [](char ch) -> bool { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || (ch == '_') || (ch & '\x80'); // non-ascii - }, - 1); -} - -void Variables::validateNameForUserRead(StringData varName) { - validateName(varName, - [](char ch) -> bool { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch & '\x80'); // non-ascii - }, - [](char ch) -> bool { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || (ch == '_') || (ch & '\x80'); // non-ascii - }, - 1); -} - void Variables::setValue(Id id, const Value& value, bool isConstant) { uassert(17199, "can't use Variables::setValue to set a reserved builtin variable", id >= 0); @@ -236,7 +189,7 @@ void Variables::setDefaultRuntimeConstants(OperationContext* opCtx) { void Variables::seedVariablesWithLetParameters(ExpressionContext* const expCtx, const BSONObj letParams) { for (auto&& elem : letParams) { - Variables::validateNameForUserWrite(elem.fieldName()); + variableValidation::validateNameForUserWrite(elem.fieldName()); auto expr = Expression::parseOperand(expCtx, elem, expCtx->variablesParseState); uassert(4890500, @@ -287,7 +240,7 @@ void Variables::copyToExpCtx(const VariablesParseState& vps, ExpressionContext* } Variables::Id VariablesParseState::defineVariable(StringData name) { - // Caller should have validated before hand by using Variables::validateNameForUserWrite. + // Caller should have validated before hand by using variableValidationvalidateNameForUserWrite. massert(17275, "Can't redefine a non-user-writable variable", Variables::kBuiltinVarNameToId.find(name) == Variables::kBuiltinVarNameToId.end()); diff --git a/src/mongo/db/pipeline/variables.h b/src/mongo/db/pipeline/variables.h index 6cf5256a640..b200d04e115 100644 --- a/src/mongo/db/pipeline/variables.h +++ b/src/mongo/db/pipeline/variables.h @@ -73,8 +73,6 @@ public: Variables() = default; - static void validateNameForUserWrite(StringData varName); - static void validateNameForUserRead(StringData varName); static bool isUserDefinedVariable(Variables::Id id) { return id >= 0; } @@ -199,11 +197,6 @@ private: void setValue(Id id, const Value& value, bool isConstant); - static void validateName(StringData varName, - std::function<bool(char)> prefixPred, - std::function<bool(char)> suffixPred, - int prefixLen); - static auto getBuiltinVariableName(Variables::Id variable) { for (auto& [name, id] : kBuiltinVarNameToId) { if (variable == id) { |