Skip to content
This repository was archived by the owner on Oct 31, 2023. It is now read-only.

Commit 1e6e3b3

Browse files
alyacbEvergreen Agent
authored andcommitted
SERVER-52307 Enable dots and dollars feature flag
1 parent 5c9288f commit 1e6e3b3

File tree

7 files changed

+78
-31
lines changed

7 files changed

+78
-31
lines changed

src/mongo/db/pipeline/expression.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7226,9 +7226,11 @@ void ExpressionDateTrunc::_doAddDependencies(DepsTracker* deps) const {
72267226
}
72277227

72287228
/* -------------------------- ExpressionGetField ------------------------------ */
7229-
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(getField,
7230-
ExpressionGetField::parse,
7231-
feature_flags::gFeatureFlagDotsAndDollars);
7229+
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION(
7230+
getField,
7231+
ExpressionGetField::parse,
7232+
feature_flags::gFeatureFlagDotsAndDollars,
7233+
ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
72327234

72337235
intrusive_ptr<Expression> ExpressionGetField::parse(ExpressionContext* const expCtx,
72347236
BSONElement expr,
@@ -7335,14 +7337,18 @@ Value ExpressionGetField::serialize(const bool explain) const {
73357337
}
73367338

73377339
/* -------------------------- ExpressionSetField ------------------------------ */
7338-
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(setField,
7339-
ExpressionSetField::parse,
7340-
feature_flags::gFeatureFlagDotsAndDollars);
7340+
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION(
7341+
setField,
7342+
ExpressionSetField::parse,
7343+
feature_flags::gFeatureFlagDotsAndDollars,
7344+
ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
73417345

73427346
// $unsetField is syntactic sugar for $setField where value is set to $$REMOVE.
7343-
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(unsetField,
7344-
ExpressionSetField::parse,
7345-
feature_flags::gFeatureFlagDotsAndDollars);
7347+
REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION(
7348+
unsetField,
7349+
ExpressionSetField::parse,
7350+
feature_flags::gFeatureFlagDotsAndDollars,
7351+
ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
73467352

73477353
intrusive_ptr<Expression> ExpressionSetField::parse(ExpressionContext* const expCtx,
73487354
BSONElement expr,

src/mongo/db/pipeline/expression.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,20 @@ class DocumentSource;
8080

8181
/**
8282
* Registers a Parser so it can be called from parseExpression and friends (but only if
83-
* 'featureFlag' is enabled).
83+
* 'featureFlag' is enabled) in a feature compatibility version >= X.
8484
*
8585
* As an example, if your expression looks like {"$foo": [1,2,3]} and should be flag-guarded by
86-
* feature_flags::gFoo, you would add this line:
87-
* REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(foo, ExpressionFoo::parse, feature_flags::gFoo);
88-
*
89-
* An expression registered this way can be used in any featureCompatibilityVersion.
86+
* feature_flags::gFoo and version >= X, you would add this line:
87+
* REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION(
88+
* foo, ExpressionFoo::parse, feature_flags::gFoo, X);
9089
*/
91-
#define REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(key, parser, featureFlag) \
90+
#define REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION( \
91+
key, parser, featureFlag, minVersion) \
9292
MONGO_INITIALIZER_GENERAL( \
9393
addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
9494
(InitializerContext*) { \
9595
if (featureFlag.isEnabledAndIgnoreFCV()) { \
96-
Expression::registerExpression("$" #key, (parser), boost::none); \
96+
Expression::registerExpression("$" #key, (parser), (minVersion)); \
9797
} \
9898
}
9999

src/mongo/db/query/query_feature_flags.idl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ feature_flags:
5252
featureFlagDotsAndDollars:
5353
description: "Feature flag for allowing use of field names containing dots and dollars"
5454
cpp_varname: gFeatureFlagDotsAndDollars
55-
default: false
55+
default: true
56+
version: 5.0

src/mongo/db/update/rename_node_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "mongo/db/json.h"
3737
#include "mongo/db/pipeline/expression_context_for_test.h"
3838
#include "mongo/db/update/update_node_test_fixture.h"
39+
#include "mongo/idl/server_parameter_test_util.h"
3940
#include "mongo/unittest/death_test.h"
4041
#include "mongo/unittest/unittest.h"
4142

@@ -473,6 +474,7 @@ TEST_F(RenameNodeTest, RenameFromNonExistentPathIsNoOp) {
473474
}
474475

475476
TEST_F(RenameNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
477+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", false);
476478
auto update = fromjson("{$rename: {'a.$id': 'b'}}");
477479
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
478480
RenameNode node;
@@ -579,6 +581,7 @@ TEST_F(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
579581
}
580582

581583
TEST_F(RenameNodeTest, ApplyCannotCreateDollarPrefixedField) {
584+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", false);
582585
auto update = fromjson("{$rename: {a: '$bad'}}");
583586
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
584587
RenameNode node;

src/mongo/db/update/set_node_test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInsideSetElement) {
10531053
}
10541054

10551055
TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtStartOfPath) {
1056+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", false);
10561057
auto update = fromjson("{$set: {'$bad.a': 1}}");
10571058
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
10581059
SetNode node;

src/mongo/db/update/unset_node_test.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "mongo/db/json.h"
3737
#include "mongo/db/pipeline/expression_context_for_test.h"
3838
#include "mongo/db/update/update_node_test_fixture.h"
39+
#include "mongo/idl/server_parameter_test_util.h"
3940
#include "mongo/unittest/death_test.h"
4041
#include "mongo/unittest/unittest.h"
4142

@@ -369,18 +370,43 @@ TEST_F(UnsetNodeTest, ApplyFieldWithDot) {
369370
}
370371

371372
TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
372-
auto update = fromjson("{$unset: {'a.$id': true}}");
373-
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
374-
UnsetNode node;
375-
ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx));
376-
377-
mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
378-
setPathTaken(makeRuntimeUpdatePathForTest("a.$id"));
379-
ASSERT_THROWS_CODE_AND_WHAT(
380-
node.apply(getApplyParams(doc.root()["a"]["$id"]), getUpdateNodeApplyParams()),
381-
AssertionException,
382-
ErrorCodes::InvalidDBRef,
383-
"The DBRef $ref field must be followed by a $id field");
373+
{
374+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", false);
375+
auto update = fromjson("{$unset: {'a.$id': true}}");
376+
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
377+
UnsetNode node;
378+
ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx));
379+
380+
mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
381+
setPathTaken(makeRuntimeUpdatePathForTest("a.$id"));
382+
ASSERT_THROWS_CODE_AND_WHAT(
383+
node.apply(getApplyParams(doc.root()["a"]["$id"]), getUpdateNodeApplyParams()),
384+
AssertionException,
385+
ErrorCodes::InvalidDBRef,
386+
"The DBRef $ref field must be followed by a $id field");
387+
}
388+
{
389+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", true);
390+
auto update = fromjson("{$unset: {'a.$id': true}}");
391+
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
392+
UnsetNode node;
393+
ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx));
394+
395+
mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
396+
setPathTaken(makeRuntimeUpdatePathForTest("a.$id"));
397+
auto result =
398+
node.apply(getApplyParams(doc.root()["a"]["$id"]), getUpdateNodeApplyParams());
399+
ASSERT_FALSE(result.noop);
400+
ASSERT_FALSE(result.indexesAffected);
401+
auto updated = BSON("a" << BSON("$ref"
402+
<< "c"));
403+
ASSERT_EQUALS(updated, doc);
404+
ASSERT_FALSE(doc.isInPlaceModeEnabled());
405+
406+
assertOplogEntry(fromjson("{$unset: {'a.$id': true}}"),
407+
fromjson("{$v: 2, diff: {sa: {d: {$id: false}}}}"));
408+
ASSERT_EQUALS(getModifiedPaths(), "{a.$id}");
409+
}
384410
}
385411

386412
TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {

src/mongo/dbtests/updatetests.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "mongo/db/lasterror.h"
4545
#include "mongo/db/ops/update.h"
4646
#include "mongo/dbtests/dbtests.h"
47+
#include "mongo/idl/server_parameter_test_util.h"
4748

4849
namespace UpdateTests {
4950

@@ -1740,8 +1741,17 @@ class PreserveIdWithIndex : public SetBase { // Not using $set, but base class
17401741
class CheckNoMods : public SetBase {
17411742
public:
17421743
void run() {
1743-
_client.update(ns(), BSONObj(), BSON("i" << 5 << "$set" << BSON("q" << 3)), true);
1744-
ASSERT(error());
1744+
{
1745+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", false);
1746+
_client.update(ns(), BSONObj(), BSON("i" << 5 << "$set" << BSON("q" << 3)), true);
1747+
ASSERT(error());
1748+
}
1749+
{
1750+
RAIIServerParameterControllerForTest controller("featureFlagDotsAndDollars", true);
1751+
_client.update(ns(), BSONObj(), BSON("_id" << 52307 << "$set" << BSON("q" << 3)), true);
1752+
ASSERT_BSONOBJ_EQ(fromjson("{'_id':52307,$set:{q:3}}"),
1753+
_client.findOne(ns(), Query(BSON("_id" << 52307))));
1754+
}
17451755
}
17461756
};
17471757

0 commit comments

Comments
 (0)