summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/matcher/expression_expr_test.cpp40
-rw-r--r--src/mongo/db/pipeline/expression.cpp9
-rw-r--r--src/mongo/db/pipeline/expression_date_test.cpp3
-rw-r--r--src/mongo/db/pipeline/expression_field_path_test.cpp27
4 files changed, 40 insertions, 39 deletions
diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp
index 276c4ea1eb9..07e18df4660 100644
--- a/src/mongo/db/matcher/expression_expr_test.cpp
+++ b/src/mongo/db/matcher/expression_expr_test.cpp
@@ -832,48 +832,12 @@ TEST_F(ExprMatchTest, ExprRedactsCorrectly) {
createMatcher(fromjson("{$expr: {$eq: [\"$a\", \"$$NOW\"]}}"));
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({
- "$and": [
- {
- "HASH<a>": {
- "$_internalExprEq": "?"
- }
- },
- {
- "$expr": {
- "$eq": [
- "$HASH<a>",
- {
- "$const": "?"
- }
- ]
- }
- }
- ]
- })",
+ R"({"$expr":{"$eq":["$HASH<a>","$$NOW"]}})",
serialize(opts));
createMatcher(fromjson("{$expr: {$eq: [\"$a\", \"$$NOW\"]}}"));
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({
- "$and": [
- {
- "HASH<a>": {
- "$_internalExprEq": "?"
- }
- },
- {
- "$expr": {
- "$eq": [
- "$HASH<a>",
- {
- "$const": "?"
- }
- ]
- }
- }
- ]
- })",
+ R"({"$expr":{"$eq":["$HASH<a>","$$NOW"]}})",
serialize(opts));
createMatcher(fromjson("{$expr: {$getField: {field: \"b\", input: {a: 1, b: 2}}}}"));
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 6cdc08bca0c..125a14619a1 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -2501,6 +2501,15 @@ intrusive_ptr<Expression> ExpressionFieldPath::optimize() {
return ExpressionConstant::create(getExpressionContext(), Value());
}
+ if (_variable == Variables::kNowId || _variable == Variables::kClusterTimeId ||
+ _variable == Variables::kUserRolesId) {
+ // The agg system is allowed to replace the ExpressionFieldPath with an ExpressionConstant,
+ // which in turn would result in a plan cache entry that inlines the value of a system
+ // variable. However, the values of these system variables are not guaranteed to be constant
+ // across different executions of the same query shape, so we prohibit the optimization.
+ return intrusive_ptr<Expression>(this);
+ }
+
if (getExpressionContext()->variables.hasConstantValue(_variable)) {
return ExpressionConstant::create(
getExpressionContext(), evaluate(Document(), &(getExpressionContext()->variables)));
diff --git a/src/mongo/db/pipeline/expression_date_test.cpp b/src/mongo/db/pipeline/expression_date_test.cpp
index 1a76e1e1838..419028b9f06 100644
--- a/src/mongo/db/pipeline/expression_date_test.cpp
+++ b/src/mongo/db/pipeline/expression_date_test.cpp
@@ -2137,13 +2137,14 @@ TEST_F(ExpressionDateArithmeticsTest, OptimizesToConstant) {
dateAddExp = Expression::parseExpression(expCtx.get(), doc, expCtx->variablesParseState);
ASSERT(dynamic_cast<ExpressionConstant*>(dateAddExp->optimize().get()));
+ // Test that $$NOW will not be optimized as constant.
doc = BSON(expName << BSON("startDate"
<< "$$NOW"
<< "unit"
<< "day"
<< "amount" << 1));
dateAddExp = Expression::parseExpression(expCtx.get(), doc, expCtx->variablesParseState);
- ASSERT(dynamic_cast<ExpressionConstant*>(dateAddExp->optimize().get()));
+ ASSERT_FALSE(dynamic_cast<ExpressionConstant*>(dateAddExp->optimize().get()));
// Test that expression does not optimize to constant if some of the parameters is not a
diff --git a/src/mongo/db/pipeline/expression_field_path_test.cpp b/src/mongo/db/pipeline/expression_field_path_test.cpp
index 3ad2c5d7262..4fba45c34a2 100644
--- a/src/mongo/db/pipeline/expression_field_path_test.cpp
+++ b/src/mongo/db/pipeline/expression_field_path_test.cpp
@@ -190,6 +190,33 @@ TEST(FieldPath, NoOptimizationOnVariableWithMissingValue) {
ASSERT_FALSE(dynamic_cast<ExpressionConstant*>(optimizedExpr.get()));
}
+TEST(FieldPath, NoOptimizationOnCertainVariables) {
+ auto expCtx = ExpressionContextForTest{};
+
+ {
+ auto expr = ExpressionFieldPath::parse(&expCtx, "$$NOW", expCtx.variablesParseState);
+ ASSERT_TRUE(dynamic_cast<ExpressionFieldPath*>(expr.get()));
+
+ auto optimizedExpr = expr->optimize();
+ ASSERT_FALSE(dynamic_cast<ExpressionConstant*>(optimizedExpr.get()));
+ }
+ {
+ auto expr =
+ ExpressionFieldPath::parse(&expCtx, "$$CLUSTER_TIME", expCtx.variablesParseState);
+ ASSERT_TRUE(dynamic_cast<ExpressionFieldPath*>(expr.get()));
+
+ auto optimizedExpr = expr->optimize();
+ ASSERT_FALSE(dynamic_cast<ExpressionConstant*>(optimizedExpr.get()));
+ }
+ {
+ auto expr = ExpressionFieldPath::parse(&expCtx, "$$USER_ROLES", expCtx.variablesParseState);
+ ASSERT_TRUE(dynamic_cast<ExpressionFieldPath*>(expr.get()));
+
+ auto optimizedExpr = expr->optimize();
+ ASSERT_FALSE(dynamic_cast<ExpressionConstant*>(optimizedExpr.get()));
+ }
+}
+
TEST(FieldPath, ScalarVariableWithDottedFieldPathOptimizesToConstantMissingValue) {
auto expCtx = ExpressionContextForTest{};
auto varId = expCtx.variablesParseState.defineVariable("userVar");