summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorArun Banala <arun.banala@mongodb.com>2019-05-29 11:36:58 +0100
committerArun Banala <arun.banala@mongodb.com>2019-06-11 17:31:47 +0100
commit17cdb38b6db716dc47485a60ddff3c543e713e3d (patch)
tree71e9397c86220a4084da28d195563af3b3831507 /src
parent38d00f12ec33b6c646ed50cac7b129d2a1566321 (diff)
downloadmongo-17cdb38b6db716dc47485a60ddff3c543e713e3d.tar.gz
SERVER-41065 Make evaluate() thread safe by passing 'Variables' as a parameter
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/matcher/expression_expr.cpp7
-rw-r--r--src/mongo/db/pipeline/document_source_bucket_auto.cpp5
-rw-r--r--src/mongo/db/pipeline/document_source_graph_lookup.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_group.cpp11
-rw-r--r--src/mongo/db/pipeline/document_source_lookup.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_merge.h2
-rw-r--r--src/mongo/db/pipeline/document_source_redact.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_replace_root.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_sort.cpp2
-rw-r--r--src/mongo/db/pipeline/expression.cpp493
-rw-r--r--src/mongo/db/pipeline/expression.h183
-rw-r--r--src/mongo/db/pipeline/expression_convert_test.cpp1300
-rw-r--r--src/mongo/db/pipeline/expression_date_test.cpp235
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp291
-rw-r--r--src/mongo/db/pipeline/expression_trigonometric_test.cpp4
-rw-r--r--src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp6
-rw-r--r--src/mongo/db/pipeline/parsed_aggregation_projection_node.cpp5
17 files changed, 1487 insertions, 1065 deletions
diff --git a/src/mongo/db/matcher/expression_expr.cpp b/src/mongo/db/matcher/expression_expr.cpp
index f58c1c14ef8..f356c4aa25b 100644
--- a/src/mongo/db/matcher/expression_expr.cpp
+++ b/src/mongo/db/matcher/expression_expr.cpp
@@ -53,8 +53,13 @@ bool ExprMatchExpression::matches(const MatchableDocument* doc, MatchDetails* de
}
Document document(doc->toBSON());
+
+ // 'Variables' is not thread safe, and ExprMatchExpression may be used in a validator which
+ // processes documents from multiple threads simultaneously. Hence we make a copy of the
+ // 'Variables' object per-caller.
+ Variables variables = _expCtx->variables;
try {
- auto value = _expression->evaluate(document);
+ auto value = _expression->evaluate(document, &variables);
return value.coerceToBool();
} catch (const DBException&) {
if (MONGO_FAIL_POINT(ExprMatchExpressionMatchesReturnsFalseOnException)) {
diff --git a/src/mongo/db/pipeline/document_source_bucket_auto.cpp b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
index ff5eeeb285a..dbbf6c7b1f7 100644
--- a/src/mongo/db/pipeline/document_source_bucket_auto.cpp
+++ b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
@@ -157,7 +157,7 @@ Value DocumentSourceBucketAuto::extractKey(const Document& doc) {
return Value(BSONNULL);
}
- Value key = _groupByExpression->evaluate(doc);
+ Value key = _groupByExpression->evaluate(doc, &pExpCtx->variables);
if (_granularityRounder) {
uassert(40258,
@@ -190,7 +190,8 @@ void DocumentSourceBucketAuto::addDocumentToBucket(const pair<Value, Document>&
const size_t numAccumulators = _accumulatedFields.size();
for (size_t k = 0; k < numAccumulators; k++) {
- bucket._accums[k]->process(_accumulatedFields[k].expression->evaluate(entry.second), false);
+ bucket._accums[k]->process(
+ _accumulatedFields[k].expression->evaluate(entry.second, &pExpCtx->variables), false);
}
}
diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
index 937da2a46cc..7447f8ae51c 100644
--- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp
+++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
@@ -335,7 +335,7 @@ void DocumentSourceGraphLookUp::performSearch() {
// Make sure _input is set before calling performSearch().
invariant(_input);
- Value startingValue = _startWith->evaluate(*_input);
+ Value startingValue = _startWith->evaluate(*_input, &pExpCtx->variables);
// If _startWith evaluates to an array, treat each value as a separate starting point.
if (startingValue.isArray()) {
diff --git a/src/mongo/db/pipeline/document_source_group.cpp b/src/mongo/db/pipeline/document_source_group.cpp
index dd14584ecc9..ff46f44aba4 100644
--- a/src/mongo/db/pipeline/document_source_group.cpp
+++ b/src/mongo/db/pipeline/document_source_group.cpp
@@ -73,7 +73,7 @@ Document GroupFromFirstDocumentTransformation::applyTransformation(const Documen
MutableDocument output(_accumulatorExprs.size());
for (auto&& expr : _accumulatorExprs) {
- auto value = expr.second->evaluate(input);
+ auto value = expr.second->evaluate(input, &expr.second->getExpressionContext()->variables);
output.addField(expr.first, value.missing() ? Value(BSONNULL) : value);
}
@@ -495,8 +495,9 @@ DocumentSource::GetNextResult DocumentSourceGroup::initialize() {
dassert(numAccumulators == group.size());
for (size_t i = 0; i < numAccumulators; i++) {
- group[i]->process(_accumulatedFields[i].expression->evaluate(rootDocument),
- _doingMerge);
+ group[i]->process(
+ _accumulatedFields[i].expression->evaluate(rootDocument, &pExpCtx->variables),
+ _doingMerge);
_memoryUsageBytes += group[i]->memUsageForSorter();
}
@@ -611,7 +612,7 @@ shared_ptr<Sorter<Value, Value>::Iterator> DocumentSourceGroup::spill() {
Value DocumentSourceGroup::computeId(const Document& root) {
// If only one expression, return result directly
if (_idExpressions.size() == 1) {
- Value retValue = _idExpressions[0]->evaluate(root);
+ Value retValue = _idExpressions[0]->evaluate(root, &pExpCtx->variables);
return retValue.missing() ? Value(BSONNULL) : std::move(retValue);
}
@@ -619,7 +620,7 @@ Value DocumentSourceGroup::computeId(const Document& root) {
vector<Value> vals;
vals.reserve(_idExpressions.size());
for (size_t i = 0; i < _idExpressions.size(); i++) {
- vals.push_back(_idExpressions[i]->evaluate(root));
+ vals.push_back(_idExpressions[i]->evaluate(root, &pExpCtx->variables));
}
return Value(std::move(vals));
}
diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp
index da994cc3ca7..b2a81168a77 100644
--- a/src/mongo/db/pipeline/document_source_lookup.cpp
+++ b/src/mongo/db/pipeline/document_source_lookup.cpp
@@ -629,7 +629,7 @@ void DocumentSourceLookUp::resolveLetVariables(const Document& localDoc, Variabl
invariant(variables);
for (auto& letVar : _letVariables) {
- auto value = letVar.expression->evaluate(localDoc);
+ auto value = letVar.expression->evaluate(localDoc, &pExpCtx->variables);
variables->setConstantValue(letVar.id, value);
}
}
diff --git a/src/mongo/db/pipeline/document_source_merge.h b/src/mongo/db/pipeline/document_source_merge.h
index 811ebf97591..927c0376245 100644
--- a/src/mongo/db/pipeline/document_source_merge.h
+++ b/src/mongo/db/pipeline/document_source_merge.h
@@ -181,7 +181,7 @@ private:
BSONObjBuilder bob;
for (auto && [ name, expr ] : *_letVariables) {
- bob << name << expr->evaluate(doc);
+ bob << name << expr->evaluate(doc, &pExpCtx->variables);
}
return bob.obj();
}
diff --git a/src/mongo/db/pipeline/document_source_redact.cpp b/src/mongo/db/pipeline/document_source_redact.cpp
index 8c48726aa2f..3ff60410a95 100644
--- a/src/mongo/db/pipeline/document_source_redact.cpp
+++ b/src/mongo/db/pipeline/document_source_redact.cpp
@@ -135,7 +135,7 @@ Value DocumentSourceRedact::redactValue(const Value& in, const Document& root) {
boost::optional<Document> DocumentSourceRedact::redactObject(const Document& root) {
auto& variables = pExpCtx->variables;
- const Value expressionResult = _expression->evaluate(root);
+ const Value expressionResult = _expression->evaluate(root, &variables);
ValueComparator simpleValueCmp;
if (simpleValueCmp.evaluate(expressionResult == keepVal)) {
diff --git a/src/mongo/db/pipeline/document_source_replace_root.cpp b/src/mongo/db/pipeline/document_source_replace_root.cpp
index 4bbbffdb628..41ff856cdd0 100644
--- a/src/mongo/db/pipeline/document_source_replace_root.cpp
+++ b/src/mongo/db/pipeline/document_source_replace_root.cpp
@@ -60,7 +60,7 @@ public:
Document applyTransformation(const Document& input) final {
// Extract subdocument in the form of a Value.
- Value newRoot = _newRoot->evaluate(input);
+ Value newRoot = _newRoot->evaluate(input, &_expCtx->variables);
// The newRoot expression, if it exists, must evaluate to an object.
uassert(40228,
diff --git a/src/mongo/db/pipeline/document_source_sort.cpp b/src/mongo/db/pipeline/document_source_sort.cpp
index e9f86b947ed..395d517ce2d 100644
--- a/src/mongo/db/pipeline/document_source_sort.cpp
+++ b/src/mongo/db/pipeline/document_source_sort.cpp
@@ -423,7 +423,7 @@ StatusWith<Value> DocumentSourceSort::extractKeyPart(const Document& doc,
plainKey = key.getValue();
} else {
invariant(patternPart.expression);
- plainKey = patternPart.expression->evaluate(doc);
+ plainKey = patternPart.expression->evaluate(doc, &pExpCtx->variables);
}
return getCollationComparisonKey(plainKey);
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index d6068398342..c1bf5957066 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -264,7 +264,7 @@ const char* ExpressionAbs::getOpName() const {
/* ------------------------- ExpressionAdd ----------------------------- */
-Value ExpressionAdd::evaluate(const Document& root) const {
+Value ExpressionAdd::evaluate(const Document& root, Variables* variables) const {
// We'll try to return the narrowest possible result value while avoiding overflow, loss
// of precision due to intermediate rounding or implicit use of decimal types. To do that,
// compute a compensated sum for non-decimal values and a separate decimal sum for decimal
@@ -276,7 +276,7 @@ Value ExpressionAdd::evaluate(const Document& root) const {
const size_t n = _children.size();
for (size_t i = 0; i < n; ++i) {
- Value val = _children[i]->evaluate(root);
+ Value val = _children[i]->evaluate(root, variables);
switch (val.getType()) {
case NumberDecimal:
@@ -346,8 +346,8 @@ const char* ExpressionAdd::getOpName() const {
/* ------------------------- ExpressionAllElementsTrue -------------------------- */
-Value ExpressionAllElementsTrue::evaluate(const Document& root) const {
- const Value arr = _children[0]->evaluate(root);
+Value ExpressionAllElementsTrue::evaluate(const Document& root, Variables* variables) const {
+ const Value arr = _children[0]->evaluate(root, variables);
uassert(17040,
str::stream() << getOpName() << "'s argument must be an array, but is "
<< typeName(arr.getType()),
@@ -424,10 +424,10 @@ intrusive_ptr<Expression> ExpressionAnd::optimize() {
return pE;
}
-Value ExpressionAnd::evaluate(const Document& root) const {
+Value ExpressionAnd::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
for (size_t i = 0; i < n; ++i) {
- Value pValue(_children[i]->evaluate(root));
+ Value pValue(_children[i]->evaluate(root, variables));
if (!pValue.coerceToBool())
return Value(false);
}
@@ -442,8 +442,8 @@ const char* ExpressionAnd::getOpName() const {
/* ------------------------- ExpressionAnyElementTrue -------------------------- */
-Value ExpressionAnyElementTrue::evaluate(const Document& root) const {
- const Value arr = _children[0]->evaluate(root);
+Value ExpressionAnyElementTrue::evaluate(const Document& root, Variables* variables) const {
+ const Value arr = _children[0]->evaluate(root, variables);
uassert(17041,
str::stream() << getOpName() << "'s argument must be an array, but is "
<< typeName(arr.getType()),
@@ -464,11 +464,11 @@ const char* ExpressionAnyElementTrue::getOpName() const {
/* ---------------------- ExpressionArray --------------------------- */
-Value ExpressionArray::evaluate(const Document& root) const {
+Value ExpressionArray::evaluate(const Document& root, Variables* variables) const {
vector<Value> values;
values.reserve(_children.size());
for (auto&& expr : _children) {
- Value elemVal = expr->evaluate(root);
+ Value elemVal = expr->evaluate(root, variables);
values.push_back(elemVal.missing() ? Value(BSONNULL) : std::move(elemVal));
}
return Value(std::move(values));
@@ -495,7 +495,8 @@ intrusive_ptr<Expression> ExpressionArray::optimize() {
// If all values in ExpressionArray are constant evaluate to ExpressionConstant.
if (allValuesConstant) {
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document()));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document(), &(getExpressionContext()->variables)));
}
return this;
}
@@ -507,9 +508,9 @@ const char* ExpressionArray::getOpName() const {
/* ------------------------- ExpressionArrayElemAt -------------------------- */
-Value ExpressionArrayElemAt::evaluate(const Document& root) const {
- const Value array = _children[0]->evaluate(root);
- const Value indexArg = _children[1]->evaluate(root);
+Value ExpressionArrayElemAt::evaluate(const Document& root, Variables* variables) const {
+ const Value array = _children[0]->evaluate(root, variables);
+ const Value indexArg = _children[1]->evaluate(root, variables);
if (array.nullish() || indexArg.nullish()) {
return Value(BSONNULL);
@@ -549,8 +550,8 @@ const char* ExpressionArrayElemAt::getOpName() const {
/* ------------------------- ExpressionObjectToArray -------------------------- */
-Value ExpressionObjectToArray::evaluate(const Document& root) const {
- const Value targetVal = _children[0]->evaluate(root);
+Value ExpressionObjectToArray::evaluate(const Document& root, Variables* variables) const {
+ const Value targetVal = _children[0]->evaluate(root, variables);
if (targetVal.nullish()) {
return Value(BSONNULL);
@@ -581,8 +582,8 @@ const char* ExpressionObjectToArray::getOpName() const {
}
/* ------------------------- ExpressionArrayToObject -------------------------- */
-Value ExpressionArrayToObject::evaluate(const Document& root) const {
- const Value input = _children[0]->evaluate(root);
+Value ExpressionArrayToObject::evaluate(const Document& root, Variables* variables) const {
+ const Value input = _children[0]->evaluate(root, variables);
if (input.nullish()) {
return Value(BSONNULL);
}
@@ -729,8 +730,8 @@ void ExpressionCoerceToBool::_doAddDependencies(DepsTracker* deps) const {
pExpression->addDependencies(deps);
}
-Value ExpressionCoerceToBool::evaluate(const Document& root) const {
- Value pResult(pExpression->evaluate(root));
+Value ExpressionCoerceToBool::evaluate(const Document& root, Variables* variables) const {
+ Value pResult(pExpression->evaluate(root, variables));
bool b = pResult.coerceToBool();
if (b)
return Value(true);
@@ -809,9 +810,9 @@ static const CmpLookup cmpLookup[7] = {
};
}
-Value ExpressionCompare::evaluate(const Document& root) const {
- Value pLeft(_children[0]->evaluate(root));
- Value pRight(_children[1]->evaluate(root));
+Value ExpressionCompare::evaluate(const Document& root, Variables* variables) const {
+ Value pLeft(_children[0]->evaluate(root, variables));
+ Value pRight(_children[1]->evaluate(root, variables));
int cmp = getExpressionContext()->getValueComparator().compare(pLeft, pRight);
@@ -837,12 +838,12 @@ const char* ExpressionCompare::getOpName() const {
/* ------------------------- ExpressionConcat ----------------------------- */
-Value ExpressionConcat::evaluate(const Document& root) const {
+Value ExpressionConcat::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
StringBuilder result;
for (size_t i = 0; i < n; ++i) {
- Value val = _children[i]->evaluate(root);
+ Value val = _children[i]->evaluate(root, variables);
if (val.nullish())
return Value(BSONNULL);
@@ -863,12 +864,12 @@ const char* ExpressionConcat::getOpName() const {
/* ------------------------- ExpressionConcatArrays ----------------------------- */
-Value ExpressionConcatArrays::evaluate(const Document& root) const {
+Value ExpressionConcatArrays::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
vector<Value> values;
for (size_t i = 0; i < n; ++i) {
- Value val = _children[i]->evaluate(root);
+ Value val = _children[i]->evaluate(root, variables);
if (val.nullish()) {
return Value(BSONNULL);
}
@@ -891,10 +892,10 @@ const char* ExpressionConcatArrays::getOpName() const {
/* ----------------------- ExpressionCond ------------------------------ */
-Value ExpressionCond::evaluate(const Document& root) const {
- Value pCond(_children[0]->evaluate(root));
+Value ExpressionCond::evaluate(const Document& root, Variables* variables) const {
+ Value pCond(_children[0]->evaluate(root, variables));
int idx = pCond.coerceToBool() ? 1 : 2;
- return _children[idx]->evaluate(root);
+ return _children[idx]->evaluate(root, variables);
}
intrusive_ptr<Expression> ExpressionCond::parse(
@@ -965,7 +966,7 @@ void ExpressionConstant::_doAddDependencies(DepsTracker* deps) const {
/* nothing to do */
}
-Value ExpressionConstant::evaluate(const Document& root) const {
+Value ExpressionConstant::evaluate(const Document& root, Variables* variables) const {
return _value;
}
@@ -987,14 +988,15 @@ namespace {
boost::optional<TimeZone> makeTimeZone(const TimeZoneDatabase* tzdb,
const Document& root,
- const Expression* timeZone) {
+ const Expression* timeZone,
+ Variables* variables) {
invariant(tzdb);
if (!timeZone) {
return mongo::TimeZoneDatabase::utcZone();
}
- auto timeZoneId = timeZone->evaluate(root);
+ auto timeZoneId = timeZone->evaluate(root, variables);
if (timeZoneId.nullish()) {
return boost::none;
@@ -1176,8 +1178,10 @@ intrusive_ptr<Expression> ExpressionDateFromParts::optimize() {
_isoWeek,
_isoDayOfWeek,
_timeZone})) {
+
// Everything is a constant, so we can turn into a constant.
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
@@ -1203,13 +1207,14 @@ bool ExpressionDateFromParts::evaluateNumberWithDefault(const Document& root,
intrusive_ptr<Expression> field,
StringData fieldName,
long long defaultValue,
- long long* returnValue) const {
+ long long* returnValue,
+ Variables* variables) const {
if (!field) {
*returnValue = defaultValue;
return true;
}
- auto fieldValue = field->evaluate(root);
+ auto fieldValue = field->evaluate(root, variables);
if (fieldValue.nullish()) {
return false;
@@ -1227,18 +1232,20 @@ bool ExpressionDateFromParts::evaluateNumberWithDefault(const Document& root,
return true;
}
-Value ExpressionDateFromParts::evaluate(const Document& root) const {
+Value ExpressionDateFromParts::evaluate(const Document& root, Variables* variables) const {
long long hour, minute, second, millisecond;
- if (!evaluateNumberWithDefault(root, _hour, "hour"_sd, 0, &hour) ||
- !evaluateNumberWithDefault(root, _minute, "minute"_sd, 0, &minute) ||
- !evaluateNumberWithDefault(root, _second, "second"_sd, 0, &second) ||
- !evaluateNumberWithDefault(root, _millisecond, "millisecond"_sd, 0, &millisecond)) {
+ if (!evaluateNumberWithDefault(root, _hour, "hour"_sd, 0, &hour, variables) ||
+ !evaluateNumberWithDefault(root, _minute, "minute"_sd, 0, &minute, variables) ||
+ !evaluateNumberWithDefault(root, _second, "second"_sd, 0, &second, variables) ||
+ !evaluateNumberWithDefault(
+ root, _millisecond, "millisecond"_sd, 0, &millisecond, variables)) {
// One of the evaluated inputs in nullish.
return Value(BSONNULL);
}
- auto timeZone = makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get());
+ auto timeZone =
+ makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get(), variables);
if (!timeZone) {
return Value(BSONNULL);
@@ -1247,9 +1254,9 @@ Value ExpressionDateFromParts::evaluate(const Document& root) const {
if (_year) {
long long year, month, day;
- if (!evaluateNumberWithDefault(root, _year, "year"_sd, 1970, &year) ||
- !evaluateNumberWithDefault(root, _month, "month"_sd, 1, &month) ||
- !evaluateNumberWithDefault(root, _day, "day"_sd, 1, &day)) {
+ if (!evaluateNumberWithDefault(root, _year, "year"_sd, 1970, &year, variables) ||
+ !evaluateNumberWithDefault(root, _month, "month"_sd, 1, &month, variables) ||
+ !evaluateNumberWithDefault(root, _day, "day"_sd, 1, &day, variables)) {
// One of the evaluated inputs in nullish.
return Value(BSONNULL);
}
@@ -1268,9 +1275,11 @@ Value ExpressionDateFromParts::evaluate(const Document& root) const {
if (_isoWeekYear) {
long long isoWeekYear, isoWeek, isoDayOfWeek;
- if (!evaluateNumberWithDefault(root, _isoWeekYear, "isoWeekYear"_sd, 1970, &isoWeekYear) ||
- !evaluateNumberWithDefault(root, _isoWeek, "isoWeek"_sd, 1, &isoWeek) ||
- !evaluateNumberWithDefault(root, _isoDayOfWeek, "isoDayOfWeek"_sd, 1, &isoDayOfWeek)) {
+ if (!evaluateNumberWithDefault(
+ root, _isoWeekYear, "isoWeekYear"_sd, 1970, &isoWeekYear, variables) ||
+ !evaluateNumberWithDefault(root, _isoWeek, "isoWeek"_sd, 1, &isoWeek, variables) ||
+ !evaluateNumberWithDefault(
+ root, _isoDayOfWeek, "isoDayOfWeek"_sd, 1, &isoDayOfWeek, variables)) {
// One of the evaluated inputs in nullish.
return Value(BSONNULL);
}
@@ -1405,7 +1414,8 @@ intrusive_ptr<Expression> ExpressionDateFromString::optimize() {
if (ExpressionConstant::allNullOrConstant(
{_dateString, _timeZone, _format, _onNull, _onError})) {
// Everything is a constant, so we can turn into a constant.
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
}
@@ -1420,14 +1430,14 @@ Value ExpressionDateFromString::serialize(bool explain) const {
{"onError", _onError ? _onError->serialize(explain) : Value()}}}});
}
-Value ExpressionDateFromString::evaluate(const Document& root) const {
- const Value dateString = _dateString->evaluate(root);
+Value ExpressionDateFromString::evaluate(const Document& root, Variables* variables) const {
+ const Value dateString = _dateString->evaluate(root, variables);
Value formatValue;
// Eagerly validate the format parameter, ignoring if nullish since the input string nullish
// behavior takes precedence.
if (_format) {
- formatValue = _format->evaluate(root);
+ formatValue = _format->evaluate(root, variables);
if (!formatValue.nullish()) {
uassert(40684,
str::stream() << "$dateFromString requires that 'format' be a string, found: "
@@ -1442,11 +1452,12 @@ Value ExpressionDateFromString::evaluate(const Document& root) const {
// Evaluate the timezone parameter before checking for nullish input, as this will throw an
// exception for an invalid timezone string.
- auto timeZone = makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get());
+ auto timeZone =
+ makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get(), variables);
// Behavior for nullish input takes precedence over other nullish elements.
if (dateString.nullish()) {
- return _onNull ? _onNull->evaluate(root) : Value(BSONNULL);
+ return _onNull ? _onNull->evaluate(root, variables) : Value(BSONNULL);
}
try {
@@ -1476,7 +1487,7 @@ Value ExpressionDateFromString::evaluate(const Document& root) const {
getExpressionContext()->timeZoneDatabase->fromString(dateTimeString, timeZone.get()));
} catch (const ExceptionFor<ErrorCodes::ConversionFailure>&) {
if (_onError) {
- return _onError->evaluate(root);
+ return _onError->evaluate(root, variables);
}
throw;
}
@@ -1563,7 +1574,8 @@ intrusive_ptr<Expression> ExpressionDateToParts::optimize() {
if (ExpressionConstant::allNullOrConstant({_date, _iso8601, _timeZone})) {
// Everything is a constant, so we can turn into a constant.
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
@@ -1577,12 +1589,13 @@ Value ExpressionDateToParts::serialize(bool explain) const {
{"iso8601", _iso8601 ? _iso8601->serialize(explain) : Value()}}}});
}
-boost::optional<int> ExpressionDateToParts::evaluateIso8601Flag(const Document& root) const {
+boost::optional<int> ExpressionDateToParts::evaluateIso8601Flag(const Document& root,
+ Variables* variables) const {
if (!_iso8601) {
return false;
}
- auto iso8601Output = _iso8601->evaluate(root);
+ auto iso8601Output = _iso8601->evaluate(root, variables);
if (iso8601Output.nullish()) {
return boost::none;
@@ -1596,15 +1609,16 @@ boost::optional<int> ExpressionDateToParts::evaluateIso8601Flag(const Document&
return iso8601Output.getBool();
}
-Value ExpressionDateToParts::evaluate(const Document& root) const {
- const Value date = _date->evaluate(root);
+Value ExpressionDateToParts::evaluate(const Document& root, Variables* variables) const {
+ const Value date = _date->evaluate(root, variables);
- auto timeZone = makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get());
+ auto timeZone =
+ makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get(), variables);
if (!timeZone) {
return Value(BSONNULL);
}
- auto iso8601 = evaluateIso8601Flag(root);
+ auto iso8601 = evaluateIso8601Flag(root, variables);
if (!iso8601) {
return Value(BSONNULL);
}
@@ -1718,7 +1732,8 @@ intrusive_ptr<Expression> ExpressionDateToString::optimize() {
if (ExpressionConstant::allNullOrConstant({_date, _format, _timeZone, _onNull})) {
// Everything is a constant, so we can turn into a constant.
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
@@ -1733,14 +1748,14 @@ Value ExpressionDateToString::serialize(bool explain) const {
{"onNull", _onNull ? _onNull->serialize(explain) : Value()}}}});
}
-Value ExpressionDateToString::evaluate(const Document& root) const {
- const Value date = _date->evaluate(root);
+Value ExpressionDateToString::evaluate(const Document& root, Variables* variables) const {
+ const Value date = _date->evaluate(root, variables);
Value formatValue;
// Eagerly validate the format parameter, ignoring if nullish since the input date nullish
// behavior takes precedence.
if (_format) {
- formatValue = _format->evaluate(root);
+ formatValue = _format->evaluate(root, variables);
if (!formatValue.nullish()) {
uassert(18533,
str::stream() << "$dateToString requires that 'format' be a string, found: "
@@ -1755,10 +1770,11 @@ Value ExpressionDateToString::evaluate(const Document& root) const {
// Evaluate the timezone parameter before checking for nullish input, as this will throw an
// exception for an invalid timezone string.
- auto timeZone = makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get());
+ auto timeZone =
+ makeTimeZone(getExpressionContext()->timeZoneDatabase, root, _timeZone.get(), variables);
if (date.nullish()) {
- return _onNull ? _onNull->evaluate(root) : Value(BSONNULL);
+ return _onNull ? _onNull->evaluate(root, variables) : Value(BSONNULL);
}
if (!timeZone) {
@@ -1793,9 +1809,9 @@ void ExpressionDateToString::_doAddDependencies(DepsTracker* deps) const {
/* ----------------------- ExpressionDivide ---------------------------- */
-Value ExpressionDivide::evaluate(const Document& root) const {
- Value lhs = _children[0]->evaluate(root);
- Value rhs = _children[1]->evaluate(root);
+Value ExpressionDivide::evaluate(const Document& root, Variables* variables) const {
+ Value lhs = _children[0]->evaluate(root, variables);
+ Value rhs = _children[1]->evaluate(root, variables);
auto assertNonZero = [](bool nonZero) { uassert(16608, "can't $divide by zero", nonZero); };
@@ -1900,7 +1916,8 @@ intrusive_ptr<Expression> ExpressionObject::optimize() {
}
// If all values in ExpressionObject are constant evaluate to ExpressionConstant.
if (allValuesConstant) {
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document()));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document(), &(getExpressionContext()->variables)));
}
return this;
}
@@ -1911,10 +1928,10 @@ void ExpressionObject::_doAddDependencies(DepsTracker* deps) const {
}
}
-Value ExpressionObject::evaluate(const Document& root) const {
+Value ExpressionObject::evaluate(const Document& root, Variables* variables) const {
MutableDocument outputDoc;
for (auto&& pair : _expressions) {
- outputDoc.addField(pair.first, pair.second->evaluate(root));
+ outputDoc.addField(pair.first, pair.second->evaluate(root, variables));
}
return outputDoc.freezeToValue();
}
@@ -2005,7 +2022,8 @@ intrusive_ptr<Expression> ExpressionFieldPath::optimize() {
}
if (getExpressionContext()->variables.hasConstantValue(_variable)) {
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document()));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document(), &(getExpressionContext()->variables)));
}
return intrusive_ptr<Expression>(this);
@@ -2072,17 +2090,16 @@ Value ExpressionFieldPath::evaluatePath(size_t index, const Document& input) con
}
}
-Value ExpressionFieldPath::evaluate(const Document& root) const {
- auto& vars = getExpressionContext()->variables;
+Value ExpressionFieldPath::evaluate(const Document& root, Variables* variables) const {
if (_fieldPath.getPathLength() == 1) // get the whole variable
- return vars.getValue(_variable, root);
+ return variables->getValue(_variable, root);
if (_variable == Variables::kRootId) {
// ROOT is always a document so use optimized code path
return evaluatePath(1, root);
}
- Value var = vars.getValue(_variable, root);
+ Value var = variables->getValue(_variable, root);
switch (var.getType()) {
case Object:
return evaluatePath(1, var.getDocument());
@@ -2201,9 +2218,9 @@ Value ExpressionFilter::serialize(bool explain) const {
<< _filter->serialize(explain))));
}
-Value ExpressionFilter::evaluate(const Document& root) const {
+Value ExpressionFilter::evaluate(const Document& root, Variables* variables) const {
// We are guaranteed at parse time that this isn't using our _varId.
- const Value inputVal = _input->evaluate(root);
+ const Value inputVal = _input->evaluate(root, variables);
if (inputVal.nullish())
return Value(BSONNULL);
@@ -2218,11 +2235,10 @@ Value ExpressionFilter::evaluate(const Document& root) const {
return inputVal;
vector<Value> output;
- auto& vars = getExpressionContext()->variables;
for (const auto& elem : input) {
- vars.setValue(_varId, elem);
+ variables->setValue(_varId, elem);
- if (_filter->evaluate(root).coerceToBool()) {
+ if (_filter->evaluate(root, variables).coerceToBool()) {
output.push_back(std::move(elem));
}
}
@@ -2345,15 +2361,14 @@ Value ExpressionLet::serialize(bool explain) const {
DOC("$let" << DOC("vars" << vars.freeze() << "in" << _subExpression->serialize(explain))));
}
-Value ExpressionLet::evaluate(const Document& root) const {
+Value ExpressionLet::evaluate(const Document& root, Variables* variables) const {
for (const auto& item : _variables) {
// It is guaranteed at parse-time that these expressions don't use the variable ids we
// are setting
- getExpressionContext()->variables.setValue(item.first,
- item.second.expression->evaluate(root));
+ variables->setValue(item.first, item.second.expression->evaluate(root, variables));
}
- return _subExpression->evaluate(root);
+ return _subExpression->evaluate(root, variables);
}
void ExpressionLet::_doAddDependencies(DepsTracker* deps) const {
@@ -2441,9 +2456,9 @@ Value ExpressionMap::serialize(bool explain) const {
<< _each->serialize(explain))));
}
-Value ExpressionMap::evaluate(const Document& root) const {
+Value ExpressionMap::evaluate(const Document& root, Variables* variables) const {
// guaranteed at parse time that this isn't using our _varId
- const Value inputVal = _input->evaluate(root);
+ const Value inputVal = _input->evaluate(root, variables);
if (inputVal.nullish())
return Value(BSONNULL);
@@ -2459,9 +2474,9 @@ Value ExpressionMap::evaluate(const Document& root) const {
vector<Value> output;
output.reserve(input.size());
for (size_t i = 0; i < input.size(); i++) {
- getExpressionContext()->variables.setValue(_varId, input[i]);
+ variables->setValue(_varId, input[i]);
- Value toInsert = _each->evaluate(root);
+ Value toInsert = _each->evaluate(root, variables);
if (toInsert.missing())
toInsert = Value(BSONNULL); // can't insert missing values into array
@@ -2548,7 +2563,7 @@ Value ExpressionMeta::serialize(bool explain) const {
MONGO_UNREACHABLE;
}
-Value ExpressionMeta::evaluate(const Document& root) const {
+Value ExpressionMeta::evaluate(const Document& root, Variables* variables) const {
switch (_metaType) {
case MetaType::TEXT_SCORE:
return root.hasTextScore() ? Value(root.getTextScore()) : Value();
@@ -2573,9 +2588,9 @@ void ExpressionMeta::_doAddDependencies(DepsTracker* deps) const {
/* ----------------------- ExpressionMod ---------------------------- */
-Value ExpressionMod::evaluate(const Document& root) const {
- Value lhs = _children[0]->evaluate(root);
- Value rhs = _children[1]->evaluate(root);
+Value ExpressionMod::evaluate(const Document& root, Variables* variables) const {
+ Value lhs = _children[0]->evaluate(root, variables);
+ Value rhs = _children[1]->evaluate(root, variables);
BSONType leftType = lhs.getType();
BSONType rightType = rhs.getType();
@@ -2630,7 +2645,7 @@ const char* ExpressionMod::getOpName() const {
/* ------------------------- ExpressionMultiply ----------------------------- */
-Value ExpressionMultiply::evaluate(const Document& root) const {
+Value ExpressionMultiply::evaluate(const Document& root, Variables* variables) const {
/*
We'll try to return the narrowest possible result value. To do that
without creating intermediate Values, do the arithmetic for double
@@ -2645,7 +2660,7 @@ Value ExpressionMultiply::evaluate(const Document& root) const {
const size_t n = _children.size();
for (size_t i = 0; i < n; ++i) {
- Value val = _children[i]->evaluate(root);
+ Value val = _children[i]->evaluate(root, variables);
if (val.numeric()) {
BSONType oldProductType = productType;
@@ -2693,12 +2708,12 @@ const char* ExpressionMultiply::getOpName() const {
/* ----------------------- ExpressionIfNull ---------------------------- */
-Value ExpressionIfNull::evaluate(const Document& root) const {
- Value pLeft(_children[0]->evaluate(root));
+Value ExpressionIfNull::evaluate(const Document& root, Variables* variables) const {
+ Value pLeft(_children[0]->evaluate(root, variables));
if (!pLeft.nullish())
return pLeft;
- Value pRight(_children[1]->evaluate(root));
+ Value pRight(_children[1]->evaluate(root, variables));
return pRight;
}
@@ -2709,9 +2724,9 @@ const char* ExpressionIfNull::getOpName() const {
/* ----------------------- ExpressionIn ---------------------------- */
-Value ExpressionIn::evaluate(const Document& root) const {
- Value argument(_children[0]->evaluate(root));
- Value arrayOfValues(_children[1]->evaluate(root));
+Value ExpressionIn::evaluate(const Document& root, Variables* variables) const {
+ Value argument(_children[0]->evaluate(root, variables));
+ Value arrayOfValues(_children[1]->evaluate(root, variables));
uassert(40081,
str::stream() << "$in requires an array as a second argument, found: "
@@ -2753,8 +2768,8 @@ void uassertIfNotIntegralAndNonNegative(Value val,
} // namespace
-Value ExpressionIndexOfArray::evaluate(const Document& root) const {
- Value arrayArg = _children[0]->evaluate(root);
+Value ExpressionIndexOfArray::evaluate(const Document& root, Variables* variables) const {
+ Value arrayArg = _children[0]->evaluate(root, variables);
if (arrayArg.nullish()) {
return Value(BSONNULL);
@@ -2766,7 +2781,7 @@ Value ExpressionIndexOfArray::evaluate(const Document& root) const {
arrayArg.isArray());
std::vector<Value> array = arrayArg.getArray();
- auto args = evaluateAndValidateArguments(root, _children, array.size());
+ auto args = evaluateAndValidateArguments(root, _children, array.size(), variables);
for (int i = args.startIndex; i < args.endIndex; i++) {
if (getExpressionContext()->getValueComparator().evaluate(array[i] ==
args.targetOfSearch)) {
@@ -2779,11 +2794,14 @@ Value ExpressionIndexOfArray::evaluate(const Document& root) const {
}
ExpressionIndexOfArray::Arguments ExpressionIndexOfArray::evaluateAndValidateArguments(
- const Document& root, const ExpressionVector& operands, size_t arrayLength) const {
+ const Document& root,
+ const ExpressionVector& operands,
+ size_t arrayLength,
+ Variables* variables) const {
int startIndex = 0;
if (operands.size() > 2) {
- Value startIndexArg = operands[2]->evaluate(root);
+ Value startIndexArg = operands[2]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startIndex = startIndexArg.coerceToInt();
@@ -2791,13 +2809,13 @@ ExpressionIndexOfArray::Arguments ExpressionIndexOfArray::evaluateAndValidateArg
int endIndex = arrayLength;
if (operands.size() > 3) {
- Value endIndexArg = operands[3]->evaluate(root);
+ Value endIndexArg = operands[3]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(endIndexArg, getOpName(), "ending index");
// Don't let 'endIndex' exceed the length of the array.
endIndex = std::min(static_cast<int>(arrayLength), endIndexArg.coerceToInt());
}
- return {_children[1]->evaluate(root), startIndex, endIndex};
+ return {_children[1]->evaluate(root, variables), startIndex, endIndex};
}
/**
@@ -2814,9 +2832,9 @@ public:
_children = operands;
}
- virtual Value evaluate(const Document& root) const {
+ virtual Value evaluate(const Document& root, Variables* variables) const {
- auto args = evaluateAndValidateArguments(root, _children, _indexMap.size());
+ auto args = evaluateAndValidateArguments(root, _children, _indexMap.size(), variables);
auto indexVec = _indexMap.find(args.targetOfSearch);
if (indexVec == _indexMap.end())
@@ -2893,8 +2911,8 @@ bool stringHasTokenAtIndex(size_t index, const std::string& input, const std::st
} // namespace
-Value ExpressionIndexOfBytes::evaluate(const Document& root) const {
- Value stringArg = _children[0]->evaluate(root);
+Value ExpressionIndexOfBytes::evaluate(const Document& root, Variables* variables) const {
+ Value stringArg = _children[0]->evaluate(root, variables);
if (stringArg.nullish()) {
return Value(BSONNULL);
@@ -2906,7 +2924,7 @@ Value ExpressionIndexOfBytes::evaluate(const Document& root) const {
stringArg.getType() == String);
const std::string& input = stringArg.getString();
- Value tokenArg = _children[1]->evaluate(root);
+ Value tokenArg = _children[1]->evaluate(root, variables);
uassert(40092,
str::stream() << "$indexOfBytes requires a string as the second argument, found: "
<< typeName(tokenArg.getType()),
@@ -2915,14 +2933,14 @@ Value ExpressionIndexOfBytes::evaluate(const Document& root) const {
size_t startIndex = 0;
if (_children.size() > 2) {
- Value startIndexArg = _children[2]->evaluate(root);
+ Value startIndexArg = _children[2]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startIndex = static_cast<size_t>(startIndexArg.coerceToInt());
}
size_t endIndex = input.size();
if (_children.size() > 3) {
- Value endIndexArg = _children[3]->evaluate(root);
+ Value endIndexArg = _children[3]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(endIndexArg, getOpName(), "ending index");
// Don't let 'endIndex' exceed the length of the string.
endIndex = std::min(input.size(), static_cast<size_t>(endIndexArg.coerceToInt()));
@@ -2947,8 +2965,8 @@ const char* ExpressionIndexOfBytes::getOpName() const {
/* ----------------------- ExpressionIndexOfCP --------------------- */
-Value ExpressionIndexOfCP::evaluate(const Document& root) const {
- Value stringArg = _children[0]->evaluate(root);
+Value ExpressionIndexOfCP::evaluate(const Document& root, Variables* variables) const {
+ Value stringArg = _children[0]->evaluate(root, variables);
if (stringArg.nullish()) {
return Value(BSONNULL);
@@ -2960,7 +2978,7 @@ Value ExpressionIndexOfCP::evaluate(const Document& root) const {
stringArg.getType() == String);
const std::string& input = stringArg.getString();
- Value tokenArg = _children[1]->evaluate(root);
+ Value tokenArg = _children[1]->evaluate(root, variables);
uassert(40094,
str::stream() << "$indexOfCP requires a string as the second argument, found: "
<< typeName(tokenArg.getType()),
@@ -2969,7 +2987,7 @@ Value ExpressionIndexOfCP::evaluate(const Document& root) const {
size_t startCodePointIndex = 0;
if (_children.size() > 2) {
- Value startIndexArg = _children[2]->evaluate(root);
+ Value startIndexArg = _children[2]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startCodePointIndex = static_cast<size_t>(startIndexArg.coerceToInt());
}
@@ -2992,7 +3010,7 @@ Value ExpressionIndexOfCP::evaluate(const Document& root) const {
size_t endCodePointIndex = codePointLength;
if (_children.size() > 3) {
- Value endIndexArg = _children[3]->evaluate(root);
+ Value endIndexArg = _children[3]->evaluate(root, variables);
uassertIfNotIntegralAndNonNegative(endIndexArg, getOpName(), "ending index");
// Don't let 'endCodePointIndex' exceed the number of code points in the string.
@@ -3049,9 +3067,9 @@ const char* ExpressionLn::getOpName() const {
/* ----------------------- ExpressionLog ---------------------------- */
-Value ExpressionLog::evaluate(const Document& root) const {
- Value argVal = _children[0]->evaluate(root);
- Value baseVal = _children[1]->evaluate(root);
+Value ExpressionLog::evaluate(const Document& root, Variables* variables) const {
+ Value argVal = _children[0]->evaluate(root, variables);
+ Value baseVal = _children[1]->evaluate(root, variables);
if (argVal.nullish() || baseVal.nullish())
return Value(BSONNULL);
@@ -3143,8 +3161,8 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
// If all the operands are constant expressions, collapse the expression into one constant
// expression.
if (constOperandCount == _children.size()) {
- return intrusive_ptr<Expression>(
- ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
+ return intrusive_ptr<Expression>(ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document(), &(getExpressionContext()->variables))));
}
// If the expression is associative, we can collapse all the consecutive constant operands into
@@ -3187,8 +3205,9 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
if (constExpressions.size() > 1) {
ExpressionVector childrenSave = std::move(_children);
_children = std::move(constExpressions);
- optimizedOperands.emplace_back(
- ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
+ optimizedOperands.emplace_back(ExpressionConstant::create(
+ getExpressionContext(),
+ evaluate(Document(), &(getExpressionContext()->variables))));
_children = std::move(childrenSave);
} else {
optimizedOperands.insert(
@@ -3202,8 +3221,9 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
if (constExpressions.size() > 1) {
_children = std::move(constExpressions);
- optimizedOperands.emplace_back(
- ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
+ optimizedOperands.emplace_back(ExpressionConstant::create(
+ getExpressionContext(),
+ evaluate(Document(), &(getExpressionContext()->variables))));
} else {
optimizedOperands.insert(
optimizedOperands.end(), constExpressions.begin(), constExpressions.end());
@@ -3236,8 +3256,8 @@ Value ExpressionNary::serialize(bool explain) const {
/* ------------------------- ExpressionNot ----------------------------- */
-Value ExpressionNot::evaluate(const Document& root) const {
- Value pOp(_children[0]->evaluate(root));
+Value ExpressionNot::evaluate(const Document& root, Variables* variables) const {
+ Value pOp(_children[0]->evaluate(root, variables));
bool b = pOp.coerceToBool();
return Value(!b);
@@ -3250,10 +3270,10 @@ const char* ExpressionNot::getOpName() const {
/* -------------------------- ExpressionOr ----------------------------- */
-Value ExpressionOr::evaluate(const Document& root) const {
+Value ExpressionOr::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
for (size_t i = 0; i < n; ++i) {
- Value pValue(_children[i]->evaluate(root));
+ Value pValue(_children[i]->evaluate(root, variables));
if (pValue.coerceToBool())
return Value(true);
}
@@ -3423,9 +3443,9 @@ intrusive_ptr<Expression> ExpressionPow::create(
return expr;
}
-Value ExpressionPow::evaluate(const Document& root) const {
- Value baseVal = _children[0]->evaluate(root);
- Value expVal = _children[1]->evaluate(root);
+Value ExpressionPow::evaluate(const Document& root, Variables* variables) const {
+ Value baseVal = _children[0]->evaluate(root, variables);
+ Value expVal = _children[1]->evaluate(root, variables);
if (baseVal.nullish() || expVal.nullish())
return Value(BSONNULL);
@@ -3541,9 +3561,9 @@ const char* ExpressionPow::getOpName() const {
/* ------------------------- ExpressionRange ------------------------------ */
-Value ExpressionRange::evaluate(const Document& root) const {
- Value startVal(_children[0]->evaluate(root));
- Value endVal(_children[1]->evaluate(root));
+Value ExpressionRange::evaluate(const Document& root, Variables* variables) const {
+ Value startVal(_children[0]->evaluate(root, variables));
+ Value endVal(_children[1]->evaluate(root, variables));
uassert(34443,
str::stream() << "$range requires a numeric starting value, found value of type: "
@@ -3570,7 +3590,7 @@ Value ExpressionRange::evaluate(const Document& root) const {
int step = 1;
if (_children.size() == 3) {
// A step was specified by the user.
- Value stepVal(_children[2]->evaluate(root));
+ Value stepVal(_children[2]->evaluate(root, variables));
uassert(34447,
str::stream() << "$range requires a numeric step value, found value of type:"
@@ -3644,8 +3664,8 @@ intrusive_ptr<Expression> ExpressionReduce::parse(
expCtx, std::move(input), std::move(initial), std::move(in), thisVar, valueVar);
}
-Value ExpressionReduce::evaluate(const Document& root) const {
- Value inputVal = _input->evaluate(root);
+Value ExpressionReduce::evaluate(const Document& root, Variables* variables) const {
+ Value inputVal = _input->evaluate(root, variables);
if (inputVal.nullish()) {
return Value(BSONNULL);
@@ -3656,14 +3676,13 @@ Value ExpressionReduce::evaluate(const Document& root) const {
<< inputVal.toString(),
inputVal.isArray());
- Value accumulatedValue = _initial->evaluate(root);
- auto& vars = getExpressionContext()->variables;
+ Value accumulatedValue = _initial->evaluate(root, variables);
for (auto&& elem : inputVal.getArray()) {
- vars.setValue(_thisVar, elem);
- vars.setValue(_valueVar, accumulatedValue);
+ variables->setValue(_thisVar, elem);
+ variables->setValue(_valueVar, accumulatedValue);
- accumulatedValue = _in->evaluate(root);
+ accumulatedValue = _in->evaluate(root, variables);
}
return accumulatedValue;
@@ -3691,8 +3710,8 @@ Value ExpressionReduce::serialize(bool explain) const {
/* ------------------------ ExpressionReverseArray ------------------------ */
-Value ExpressionReverseArray::evaluate(const Document& root) const {
- Value input(_children[0]->evaluate(root));
+Value ExpressionReverseArray::evaluate(const Document& root, Variables* variables) const {
+ Value input(_children[0]->evaluate(root, variables));
if (input.nullish()) {
return Value(BSONNULL);
@@ -3728,9 +3747,9 @@ ValueSet arrayToSet(const Value& val, const ValueComparator& valueComparator) {
/* ----------------------- ExpressionSetDifference ---------------------------- */
-Value ExpressionSetDifference::evaluate(const Document& root) const {
- const Value lhs = _children[0]->evaluate(root);
- const Value rhs = _children[1]->evaluate(root);
+Value ExpressionSetDifference::evaluate(const Document& root, Variables* variables) const {
+ const Value lhs = _children[0]->evaluate(root, variables);
+ const Value rhs = _children[1]->evaluate(root, variables);
if (lhs.nullish() || rhs.nullish()) {
return Value(BSONNULL);
@@ -3774,13 +3793,13 @@ void ExpressionSetEquals::validateArguments(const ExpressionVector& args) const
args.size() >= 2);
}
-Value ExpressionSetEquals::evaluate(const Document& root) const {
+Value ExpressionSetEquals::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
const auto& valueComparator = getExpressionContext()->getValueComparator();
ValueSet lhs = valueComparator.makeOrderedValueSet();
for (size_t i = 0; i < n; i++) {
- const Value nextEntry = _children[i]->evaluate(root);
+ const Value nextEntry = _children[i]->evaluate(root, variables);
uassert(17044,
str::stream() << "All operands of $setEquals must be arrays. One "
<< "argument is of type: "
@@ -3811,12 +3830,12 @@ const char* ExpressionSetEquals::getOpName() const {
/* ----------------------- ExpressionSetIntersection ---------------------------- */
-Value ExpressionSetIntersection::evaluate(const Document& root) const {
+Value ExpressionSetIntersection::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
const auto& valueComparator = getExpressionContext()->getValueComparator();
ValueSet currentIntersection = valueComparator.makeOrderedValueSet();
for (size_t i = 0; i < n; i++) {
- const Value nextEntry = _children[i]->evaluate(root);
+ const Value nextEntry = _children[i]->evaluate(root, variables);
if (nextEntry.nullish()) {
return Value(BSONNULL);
}
@@ -3872,9 +3891,9 @@ Value setIsSubsetHelper(const vector<Value>& lhs, const ValueSet& rhs) {
}
}
-Value ExpressionSetIsSubset::evaluate(const Document& root) const {
- const Value lhs = _children[0]->evaluate(root);
- const Value rhs = _children[1]->evaluate(root);
+Value ExpressionSetIsSubset::evaluate(const Document& root, Variables* variables) const {
+ const Value lhs = _children[0]->evaluate(root, variables);
+ const Value rhs = _children[1]->evaluate(root, variables);
uassert(17046,
str::stream() << "both operands of $setIsSubset must be arrays. First "
@@ -3907,8 +3926,8 @@ public:
_children = operands;
}
- virtual Value evaluate(const Document& root) const {
- const Value lhs = _children[0]->evaluate(root);
+ virtual Value evaluate(const Document& root, Variables* variables) const {
+ const Value lhs = _children[0]->evaluate(root, variables);
uassert(17310,
str::stream() << "both operands of $setIsSubset must be arrays. First "
@@ -3955,11 +3974,11 @@ const char* ExpressionSetIsSubset::getOpName() const {
/* ----------------------- ExpressionSetUnion ---------------------------- */
-Value ExpressionSetUnion::evaluate(const Document& root) const {
+Value ExpressionSetUnion::evaluate(const Document& root, Variables* variables) const {
ValueSet unionedSet = getExpressionContext()->getValueComparator().makeOrderedValueSet();
const size_t n = _children.size();
for (size_t i = 0; i < n; i++) {
- const Value newEntries = _children[i]->evaluate(root);
+ const Value newEntries = _children[i]->evaluate(root, variables);
if (newEntries.nullish()) {
return Value(BSONNULL);
}
@@ -3981,8 +4000,8 @@ const char* ExpressionSetUnion::getOpName() const {
/* ----------------------- ExpressionIsArray ---------------------------- */
-Value ExpressionIsArray::evaluate(const Document& root) const {
- Value argument = _children[0]->evaluate(root);
+Value ExpressionIsArray::evaluate(const Document& root, Variables* variables) const {
+ Value argument = _children[0]->evaluate(root, variables);
return Value(argument.isArray());
}
@@ -3993,12 +4012,12 @@ const char* ExpressionIsArray::getOpName() const {
/* ----------------------- ExpressionSlice ---------------------------- */
-Value ExpressionSlice::evaluate(const Document& root) const {
+Value ExpressionSlice::evaluate(const Document& root, Variables* variables) const {
const size_t n = _children.size();
- Value arrayVal = _children[0]->evaluate(root);
+ Value arrayVal = _children[0]->evaluate(root, variables);
// Could be either a start index or the length from 0.
- Value arg2 = _children[1]->evaluate(root);
+ Value arg2 = _children[1]->evaluate(root, variables);
if (arrayVal.nullish() || arg2.nullish()) {
return Value(BSONNULL);
@@ -4049,7 +4068,7 @@ Value ExpressionSlice::evaluate(const Document& root) const {
start = std::min(array.size(), size_t(startInt));
}
- Value countVal = _children[2]->evaluate(root);
+ Value countVal = _children[2]->evaluate(root, variables);
if (countVal.nullish()) {
return Value(BSONNULL);
@@ -4084,8 +4103,8 @@ const char* ExpressionSlice::getOpName() const {
/* ----------------------- ExpressionSize ---------------------------- */
-Value ExpressionSize::evaluate(const Document& root) const {
- Value array = _children[0]->evaluate(root);
+Value ExpressionSize::evaluate(const Document& root, Variables* variables) const {
+ Value array = _children[0]->evaluate(root, variables);
uassert(17124,
str::stream() << "The argument to $size must be an array, but was of type: "
@@ -4101,9 +4120,9 @@ const char* ExpressionSize::getOpName() const {
/* ----------------------- ExpressionSplit --------------------------- */
-Value ExpressionSplit::evaluate(const Document& root) const {
- Value inputArg = _children[0]->evaluate(root);
- Value separatorArg = _children[1]->evaluate(root);
+Value ExpressionSplit::evaluate(const Document& root, Variables* variables) const {
+ Value inputArg = _children[0]->evaluate(root, variables);
+ Value separatorArg = _children[1]->evaluate(root, variables);
if (inputArg.nullish() || separatorArg.nullish()) {
return Value(BSONNULL);
@@ -4179,9 +4198,9 @@ const char* ExpressionSqrt::getOpName() const {
/* ----------------------- ExpressionStrcasecmp ---------------------------- */
-Value ExpressionStrcasecmp::evaluate(const Document& root) const {
- Value pString1(_children[0]->evaluate(root));
- Value pString2(_children[1]->evaluate(root));
+Value ExpressionStrcasecmp::evaluate(const Document& root, Variables* variables) const {
+ Value pString1(_children[0]->evaluate(root, variables));
+ Value pString2(_children[1]->evaluate(root, variables));
/* boost::iequals returns a bool not an int so strings must actually be allocated */
string str1 = boost::to_upper_copy(pString1.coerceToString());
@@ -4203,10 +4222,10 @@ const char* ExpressionStrcasecmp::getOpName() const {
/* ----------------------- ExpressionSubstrBytes ---------------------------- */
-Value ExpressionSubstrBytes::evaluate(const Document& root) const {
- Value pString(_children[0]->evaluate(root));
- Value pLower(_children[1]->evaluate(root));
- Value pLength(_children[2]->evaluate(root));
+Value ExpressionSubstrBytes::evaluate(const Document& root, Variables* variables) const {
+ Value pString(_children[0]->evaluate(root, variables));
+ Value pLower(_children[1]->evaluate(root, variables));
+ Value pLength(_children[2]->evaluate(root, variables));
string str = pString.coerceToString();
uassert(16034,
@@ -4268,10 +4287,10 @@ const char* ExpressionSubstrBytes::getOpName() const {
/* ----------------------- ExpressionSubstrCP ---------------------------- */
-Value ExpressionSubstrCP::evaluate(const Document& root) const {
- Value inputVal(_children[0]->evaluate(root));
- Value lowerVal(_children[1]->evaluate(root));
- Value lengthVal(_children[2]->evaluate(root));
+Value ExpressionSubstrCP::evaluate(const Document& root, Variables* variables) const {
+ Value inputVal(_children[0]->evaluate(root, variables));
+ Value lowerVal(_children[1]->evaluate(root, variables));
+ Value lengthVal(_children[2]->evaluate(root, variables));
std::string str = inputVal.coerceToString();
uassert(34450,
@@ -4343,8 +4362,8 @@ const char* ExpressionSubstrCP::getOpName() const {
/* ----------------------- ExpressionStrLenBytes ------------------------- */
-Value ExpressionStrLenBytes::evaluate(const Document& root) const {
- Value str(_children[0]->evaluate(root));
+Value ExpressionStrLenBytes::evaluate(const Document& root, Variables* variables) const {
+ Value str(_children[0]->evaluate(root, variables));
uassert(34473,
str::stream() << "$strLenBytes requires a string argument, found: "
@@ -4366,8 +4385,8 @@ const char* ExpressionStrLenBytes::getOpName() const {
/* ----------------------- ExpressionStrLenCP ------------------------- */
-Value ExpressionStrLenCP::evaluate(const Document& root) const {
- Value val(_children[0]->evaluate(root));
+Value ExpressionStrLenCP::evaluate(const Document& root, Variables* variables) const {
+ Value val(_children[0]->evaluate(root, variables));
uassert(34471,
str::stream() << "$strLenCP requires a string argument, found: "
@@ -4391,9 +4410,9 @@ const char* ExpressionStrLenCP::getOpName() const {
/* ----------------------- ExpressionSubtract ---------------------------- */
-Value ExpressionSubtract::evaluate(const Document& root) const {
- Value lhs = _children[0]->evaluate(root);
- Value rhs = _children[1]->evaluate(root);
+Value ExpressionSubtract::evaluate(const Document& root, Variables* variables) const {
+ Value lhs = _children[0]->evaluate(root, variables);
+ Value rhs = _children[1]->evaluate(root, variables);
BSONType diffType = Value::getWidestNumeric(rhs.getType(), lhs.getType());
@@ -4441,12 +4460,12 @@ const char* ExpressionSubtract::getOpName() const {
REGISTER_EXPRESSION(switch, ExpressionSwitch::parse);
-Value ExpressionSwitch::evaluate(const Document& root) const {
+Value ExpressionSwitch::evaluate(const Document& root, Variables* variables) const {
for (auto&& branch : _branches) {
- Value caseExpression(branch.first->evaluate(root));
+ Value caseExpression(branch.first->evaluate(root, variables));
if (caseExpression.coerceToBool()) {
- return branch.second->evaluate(root);
+ return branch.second->evaluate(root, variables);
}
}
@@ -4454,7 +4473,7 @@ Value ExpressionSwitch::evaluate(const Document& root) const {
"$switch could not find a matching branch for an input, and no default was specified.",
_default);
- return _default->evaluate(root);
+ return _default->evaluate(root, variables);
}
boost::intrusive_ptr<Expression> ExpressionSwitch::parse(
@@ -4577,8 +4596,8 @@ Value ExpressionSwitch::serialize(bool explain) const {
/* ------------------------- ExpressionToLower ----------------------------- */
-Value ExpressionToLower::evaluate(const Document& root) const {
- Value pString(_children[0]->evaluate(root));
+Value ExpressionToLower::evaluate(const Document& root, Variables* variables) const {
+ Value pString(_children[0]->evaluate(root, variables));
string str = pString.coerceToString();
boost::to_lower(str);
return Value(str);
@@ -4591,8 +4610,8 @@ const char* ExpressionToLower::getOpName() const {
/* ------------------------- ExpressionToUpper -------------------------- */
-Value ExpressionToUpper::evaluate(const Document& root) const {
- Value pString(_children[0]->evaluate(root));
+Value ExpressionToUpper::evaluate(const Document& root, Variables* variables) const {
+ Value pString(_children[0]->evaluate(root, variables));
string str(pString.coerceToString());
boost::to_upper(str);
return Value(str);
@@ -4714,8 +4733,8 @@ std::vector<StringData> extractCodePointsFromChars(StringData utf8String,
}
} // namespace
-Value ExpressionTrim::evaluate(const Document& root) const {
- auto unvalidatedInput = _input->evaluate(root);
+Value ExpressionTrim::evaluate(const Document& root, Variables* variables) const {
+ auto unvalidatedInput = _input->evaluate(root, variables);
if (unvalidatedInput.nullish()) {
return Value(BSONNULL);
}
@@ -4731,7 +4750,7 @@ Value ExpressionTrim::evaluate(const Document& root) const {
if (!_characters) {
return Value(doTrim(input, kDefaultTrimWhitespaceChars));
}
- auto unvalidatedUserChars = _characters->evaluate(root);
+ auto unvalidatedUserChars = _characters->evaluate(root, variables);
if (unvalidatedUserChars.nullish()) {
return Value(BSONNULL);
}
@@ -4810,7 +4829,9 @@ boost::intrusive_ptr<Expression> ExpressionTrim::optimize() {
_characters = _characters->optimize();
}
if (ExpressionConstant::allNullOrConstant({_input, _characters})) {
- return ExpressionConstant::create(getExpressionContext(), this->evaluate(Document()));
+ return ExpressionConstant::create(
+ getExpressionContext(),
+ this->evaluate(Document(), &(getExpressionContext()->variables)));
}
return this;
}
@@ -4849,10 +4870,11 @@ static Value evaluateRoundOrTrunc(const Document& root,
const std::vector<boost::intrusive_ptr<Expression>>& children,
const std::string& opName,
Decimal128::RoundingMode roundingMode,
- double (*doubleOp)(double)) {
+ double (*doubleOp)(double),
+ Variables* variables) {
constexpr auto maxPrecision = 100LL;
constexpr auto minPrecision = -20LL;
- auto numericArg = Value(children[0]->evaluate(root));
+ auto numericArg = Value(children[0]->evaluate(root, variables));
if (numericArg.nullish()) {
return Value(BSONNULL);
}
@@ -4863,7 +4885,7 @@ static Value evaluateRoundOrTrunc(const Document& root,
long long precisionValue = 0;
if (children.size() > 1) {
- auto precisionArg = Value(children[1]->evaluate(root));
+ auto precisionArg = Value(children[1]->evaluate(root, variables));
if (precisionArg.nullish()) {
return Value(BSONNULL);
}
@@ -4919,9 +4941,9 @@ static Value evaluateRoundOrTrunc(const Document& root,
}
}
-Value ExpressionRound::evaluate(const Document& root) const {
+Value ExpressionRound::evaluate(const Document& root, Variables* variables) const {
return evaluateRoundOrTrunc(
- root, _children, getOpName(), Decimal128::kRoundTiesToEven, &std::round);
+ root, _children, getOpName(), Decimal128::kRoundTiesToEven, &std::round, variables);
}
REGISTER_EXPRESSION_WITH_MIN_VERSION(
@@ -4932,9 +4954,9 @@ const char* ExpressionRound::getOpName() const {
return "$round";
}
-Value ExpressionTrunc::evaluate(const Document& root) const {
+Value ExpressionTrunc::evaluate(const Document& root, Variables* variables) const {
return evaluateRoundOrTrunc(
- root, _children, getOpName(), Decimal128::kRoundTowardZero, &std::trunc);
+ root, _children, getOpName(), Decimal128::kRoundTowardZero, &std::trunc, variables);
}
intrusive_ptr<Expression> ExpressionTrunc::parse(const intrusive_ptr<ExpressionContext>& expCtx,
@@ -4968,8 +4990,8 @@ const char* ExpressionTrunc::getOpName() const {
/* ------------------------- ExpressionType ----------------------------- */
-Value ExpressionType::evaluate(const Document& root) const {
- Value val(_children[0]->evaluate(root));
+Value ExpressionType::evaluate(const Document& root, Variables* variables) const {
+ Value val(_children[0]->evaluate(root, variables));
return Value(StringData(typeName(val.getType())));
}
@@ -5052,7 +5074,7 @@ intrusive_ptr<Expression> ExpressionZip::parse(
expCtx, useLongestLength, std::move(children), std::move(inputs), std::move(defaults));
}
-Value ExpressionZip::evaluate(const Document& root) const {
+Value ExpressionZip::evaluate(const Document& root, Variables* variables) const {
// Evaluate input values.
vector<vector<Value>> inputValues;
inputValues.reserve(_inputs.size());
@@ -5060,7 +5082,7 @@ Value ExpressionZip::evaluate(const Document& root) const {
size_t minArraySize = 0;
size_t maxArraySize = 0;
for (size_t i = 0; i < _inputs.size(); i++) {
- Value evalExpr = _inputs[i].get()->evaluate(root);
+ Value evalExpr = _inputs[i].get()->evaluate(root, variables);
if (evalExpr.nullish()) {
return Value(BSONNULL);
}
@@ -5089,7 +5111,7 @@ Value ExpressionZip::evaluate(const Document& root) const {
// If we need default values, evaluate each expression.
if (minArraySize != maxArraySize) {
for (size_t i = 0; i < _defaults.size(); i++) {
- evaluatedDefaults[i] = _defaults[i].get()->evaluate(root);
+ evaluatedDefaults[i] = _defaults[i].get()->evaluate(root, variables);
}
}
@@ -5673,16 +5695,16 @@ intrusive_ptr<Expression> ExpressionConvert::parse(
expCtx, std::move(input), std::move(to), std::move(onError), std::move(onNull));
}
-Value ExpressionConvert::evaluate(const Document& root) const {
- auto toValue = _to->evaluate(root);
- Value inputValue = _input->evaluate(root);
+Value ExpressionConvert::evaluate(const Document& root, Variables* variables) const {
+ auto toValue = _to->evaluate(root, variables);
+ Value inputValue = _input->evaluate(root, variables);
boost::optional<BSONType> targetType;
if (!toValue.nullish()) {
targetType = computeTargetType(toValue);
}
if (inputValue.nullish()) {
- return _onNull ? _onNull->evaluate(root) : Value(BSONNULL);
+ return _onNull ? _onNull->evaluate(root, variables) : Value(BSONNULL);
} else if (!targetType) {
// "to" evaluated to a nullish value.
return Value(BSONNULL);
@@ -5692,7 +5714,7 @@ Value ExpressionConvert::evaluate(const Document& root) const {
return performConversion(*targetType, inputValue);
} catch (const ExceptionFor<ErrorCodes::ConversionFailure>&) {
if (_onError) {
- return _onError->evaluate(root);
+ return _onError->evaluate(root, variables);
} else {
throw;
}
@@ -5715,7 +5737,8 @@ boost::intrusive_ptr<Expression> ExpressionConvert::optimize() {
// and _onNull values could still be legally folded if those values are not needed. Support for
// that case would add more complexity than it's worth, though.
if (ExpressionConstant::allNullOrConstant({_input, _to, _onError, _onNull})) {
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
@@ -5821,10 +5844,10 @@ auto CommonRegexParse(const boost::intrusive_ptr<ExpressionContext>& expCtx,
/* -------------------------- ExpressionRegex ------------------------------ */
ExpressionRegex::RegexExecutionState ExpressionRegex::buildInitialState(
- const Document& root) const {
- Value textInput = _input->evaluate(root);
- Value regexPattern = _regex->evaluate(root);
- Value regexOptions = _options ? _options->evaluate(root) : Value(BSONNULL);
+ const Document& root, Variables* variables) const {
+ Value textInput = _input->evaluate(root, variables);
+ Value regexPattern = _regex->evaluate(root, variables);
+ Value regexOptions = _options ? _options->evaluate(root, variables) : Value(BSONNULL);
auto executionState = _initialExecStateForConstantRegex.value_or(RegexExecutionState());
@@ -6056,8 +6079,8 @@ boost::intrusive_ptr<Expression> ExpressionRegexFind::parse(
expCtx, std::move(input), std::move(regex), std::move(options), opName);
}
-Value ExpressionRegexFind::evaluate(const Document& root) const {
- auto executionState = buildInitialState(root);
+Value ExpressionRegexFind::evaluate(const Document& root, Variables* variables) const {
+ auto executionState = buildInitialState(root, variables);
if (executionState.nullish()) {
return Value(BSONNULL);
}
@@ -6080,9 +6103,9 @@ boost::intrusive_ptr<Expression> ExpressionRegexFindAll::parse(
expCtx, std::move(input), std::move(regex), std::move(options), opName);
}
-Value ExpressionRegexFindAll::evaluate(const Document& root) const {
+Value ExpressionRegexFindAll::evaluate(const Document& root, Variables* variables) const {
std::vector<Value> output;
- auto executionState = buildInitialState(root);
+ auto executionState = buildInitialState(root, variables);
if (executionState.nullish()) {
return Value(output);
}
@@ -6144,8 +6167,8 @@ boost::intrusive_ptr<Expression> ExpressionRegexMatch::parse(
expCtx, std::move(input), std::move(regex), std::move(options), opName);
}
-Value ExpressionRegexMatch::evaluate(const Document& root) const {
- auto executionState = buildInitialState(root);
+Value ExpressionRegexMatch::evaluate(const Document& root, Variables* variables) const {
+ auto executionState = buildInitialState(root, variables);
// Return output of execute only if regex is not nullish.
return executionState.nullish() ? Value(false) : Value(execute(&executionState) > 0);
}
diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h
index 3ee13d4ea5e..8b7eecf0c72 100644
--- a/src/mongo/db/pipeline/expression.h
+++ b/src/mongo/db/pipeline/expression.h
@@ -146,9 +146,12 @@ public:
virtual Value serialize(bool explain) const = 0;
/**
- * Evaluate expression with respect to the Document given by 'root', and return the result.
+ * Evaluate the expression with respect to the Document given by 'root' and the Variables given
+ * by 'variables'. It is an error to supply a Variables argument whose built-in variables (like
+ * $$NOW) are not set. This method is thread-safe, so long as the 'variables' passed in here is
+ * not shared between threads.
*/
- virtual Value evaluate(const Document& root) const = 0;
+ virtual Value evaluate(const Document& root, Variables* variables) const = 0;
/**
* Returns information about the paths computed by this expression. This only needs to be
@@ -248,6 +251,10 @@ public:
return _children;
}
+ const boost::intrusive_ptr<ExpressionContext>& getExpressionContext() const {
+ return _expCtx;
+ }
+
protected:
using ExpressionVector = std::vector<boost::intrusive_ptr<Expression>>;
@@ -261,11 +268,6 @@ protected:
}
}
-
- const boost::intrusive_ptr<ExpressionContext>& getExpressionContext() const {
- return _expCtx;
- }
-
virtual void _doAddDependencies(DepsTracker* deps) const = 0;
/**
@@ -404,13 +406,13 @@ public:
explicit ExpressionFromAccumulator(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionFromAccumulator<Accumulator>>(expCtx) {}
- Value evaluate(const Document& root) const final {
+ Value evaluate(const Document& root, Variables* variables) const final {
Accumulator accum(this->getExpressionContext());
const auto n = this->_children.size();
// If a single array arg is given, loop through it passing each member to the accumulator.
// If a single, non-array arg is given, pass it directly to the accumulator.
if (n == 1) {
- Value singleVal = this->_children[0]->evaluate(root);
+ Value singleVal = this->_children[0]->evaluate(root, variables);
if (singleVal.getType() == Array) {
for (const Value& val : singleVal.getArray()) {
accum.process(val, false);
@@ -421,7 +423,7 @@ public:
} else {
// If multiple arguments are given, pass all arguments to the accumulator.
for (auto&& argument : this->_children) {
- accum.process(argument->evaluate(root), false);
+ accum.process(argument->evaluate(root, variables), false);
}
}
return accum.getValue(false);
@@ -460,8 +462,8 @@ public:
virtual ~ExpressionSingleNumericArg() = default;
- Value evaluate(const Document& root) const final {
- Value arg = this->_children[0]->evaluate(root);
+ Value evaluate(const Document& root, Variables* variables) const final {
+ Value arg = this->_children[0]->evaluate(root, variables);
if (arg.nullish())
return Value(BSONNULL);
@@ -494,15 +496,15 @@ public:
* 2. If either input is not numeric, it throws an error.
* 3. Call evaluateNumericArgs on the two numeric args.
*/
- Value evaluate(const Document& root) const final {
- Value arg1 = this->_children[0]->evaluate(root);
+ Value evaluate(const Document& root, Variables* variables) const final {
+ Value arg1 = this->_children[0]->evaluate(root, variables);
if (arg1.nullish())
return Value(BSONNULL);
uassert(51044,
str::stream() << this->getOpName() << " only supports numeric types, not "
<< typeName(arg1.getType()),
arg1.numeric());
- Value arg2 = this->_children[1]->evaluate(root);
+ Value arg2 = this->_children[1]->evaluate(root, variables);
if (arg2.nullish())
return Value(BSONNULL);
uassert(51045,
@@ -525,7 +527,7 @@ public:
class ExpressionConstant final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
Value serialize(bool explain) const final;
const char* getOpName() const;
@@ -593,8 +595,8 @@ class DateExpressionAcceptingTimeZone : public Expression {
public:
virtual ~DateExpressionAcceptingTimeZone() {}
- Value evaluate(const Document& root) const final {
- auto dateVal = _date->evaluate(root);
+ Value evaluate(const Document& root, Variables* variables) const final {
+ auto dateVal = _date->evaluate(root, variables);
if (dateVal.nullish()) {
return Value(BSONNULL);
}
@@ -603,7 +605,7 @@ public:
if (!_timeZone) {
return evaluateDate(date, TimeZoneDatabase::utcZone());
}
- auto timeZoneId = _timeZone->evaluate(root);
+ auto timeZoneId = _timeZone->evaluate(root, variables);
if (timeZoneId.nullish()) {
return Value(BSONNULL);
}
@@ -641,7 +643,8 @@ public:
}
if (ExpressionConstant::allNullOrConstant({_date, _timeZone})) {
// Everything is a constant, so we can turn into a constant.
- return ExpressionConstant::create(getExpressionContext(), evaluate(Document{}));
+ return ExpressionConstant::create(
+ getExpressionContext(), evaluate(Document{}, &(getExpressionContext()->variables)));
}
return this;
}
@@ -754,7 +757,7 @@ public:
explicit ExpressionAdd(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionAdd>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -776,7 +779,7 @@ public:
explicit ExpressionAllElementsTrue(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionAllElementsTrue, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -791,7 +794,7 @@ public:
: ExpressionVariadic<ExpressionAnd>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -813,7 +816,7 @@ public:
explicit ExpressionAnyElementTrue(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionAnyElementTrue, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -827,7 +830,7 @@ public:
explicit ExpressionArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionArray>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
Value serialize(bool explain) const final;
boost::intrusive_ptr<Expression> optimize() final;
const char* getOpName() const final;
@@ -843,7 +846,7 @@ public:
explicit ExpressionArrayElemAt(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionArrayElemAt, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -856,7 +859,7 @@ public:
explicit ExpressionObjectToArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionObjectToArray, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -869,7 +872,7 @@ public:
explicit ExpressionArrayToObject(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionArrayToObject, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -894,7 +897,7 @@ public:
class ExpressionCoerceToBool final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
Value serialize(bool explain) const final;
static boost::intrusive_ptr<ExpressionCoerceToBool> create(
@@ -935,7 +938,7 @@ public:
ExpressionCompare(const boost::intrusive_ptr<ExpressionContext>& expCtx, CmpOp cmpOp)
: ExpressionFixedArity<ExpressionCompare, 2>(expCtx), cmpOp(cmpOp) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
CmpOp getOp() const {
@@ -968,7 +971,7 @@ public:
explicit ExpressionConcat(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionConcat>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -986,7 +989,7 @@ public:
explicit ExpressionConcatArrays(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionConcatArrays>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1003,7 +1006,7 @@ class ExpressionCond final : public ExpressionFixedArity<ExpressionCond, 3> {
public:
explicit ExpressionCond(const boost::intrusive_ptr<ExpressionContext>& expCtx) : Base(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
static boost::intrusive_ptr<Expression> parse(
@@ -1023,7 +1026,7 @@ class ExpressionDateFromString final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document&) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1056,7 +1059,7 @@ class ExpressionDateFromParts final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1100,7 +1103,8 @@ private:
boost::intrusive_ptr<Expression> field,
StringData fieldName,
long long defaultValue,
- long long* returnValue) const;
+ long long* returnValue,
+ Variables* variables) const;
boost::intrusive_ptr<Expression>& _year;
boost::intrusive_ptr<Expression>& _month;
@@ -1119,7 +1123,7 @@ class ExpressionDateToParts final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1142,7 +1146,7 @@ private:
boost::intrusive_ptr<Expression> timeZone,
boost::intrusive_ptr<Expression> iso8601);
- boost::optional<int> evaluateIso8601Flag(const Document& root) const;
+ boost::optional<int> evaluateIso8601Flag(const Document& root, Variables* variables) const;
boost::intrusive_ptr<Expression>& _date;
boost::intrusive_ptr<Expression>& _timeZone;
@@ -1153,7 +1157,7 @@ class ExpressionDateToString final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1239,7 +1243,7 @@ public:
explicit ExpressionDivide(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionDivide, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1269,7 +1273,7 @@ public:
}
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
Value serialize(bool explain) const final;
/*
@@ -1350,7 +1354,7 @@ class ExpressionFilter final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1419,7 +1423,7 @@ public:
explicit ExpressionIfNull(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIfNull, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1433,7 +1437,7 @@ public:
explicit ExpressionIn(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIn, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1448,7 +1452,7 @@ public:
: ExpressionRangedArity<ExpressionIndexOfArray, 2, 4>(expCtx) {}
- Value evaluate(const Document& root) const;
+ Value evaluate(const Document& root, Variables* variables) const;
boost::intrusive_ptr<Expression> optimize() final;
const char* getOpName() const final;
@@ -1475,7 +1479,8 @@ protected:
*/
Arguments evaluateAndValidateArguments(const Document& root,
const ExpressionVector& operands,
- size_t arrayLength) const;
+ size_t arrayLength,
+ Variables* variables) const;
private:
class Optimized;
@@ -1487,7 +1492,7 @@ public:
explicit ExpressionIndexOfBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionIndexOfBytes, 2, 4>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1504,7 +1509,7 @@ public:
explicit ExpressionIndexOfCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionIndexOfCP, 2, 4>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1517,7 +1522,7 @@ class ExpressionLet final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1565,7 +1570,7 @@ public:
explicit ExpressionLog(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionLog, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1590,7 +1595,7 @@ class ExpressionMap final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1624,7 +1629,7 @@ private:
class ExpressionMeta final : public Expression {
public:
Value serialize(bool explain) const final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1692,7 +1697,7 @@ public:
explicit ExpressionMod(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionMod, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1706,7 +1711,7 @@ public:
explicit ExpressionMultiply(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionMultiply>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1746,7 +1751,7 @@ public:
explicit ExpressionNot(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionNot, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1766,7 +1771,7 @@ public:
class ExpressionObject final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
Value serialize(bool explain) const final;
static boost::intrusive_ptr<ExpressionObject> create(
@@ -1817,7 +1822,7 @@ public:
: ExpressionVariadic<ExpressionOr>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1846,7 +1851,7 @@ public:
}
private:
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
};
@@ -1856,7 +1861,7 @@ public:
explicit ExpressionRange(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionRange, 2, 3>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1880,7 +1885,7 @@ public:
_thisVar(thisVar),
_valueVar(valueVar) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1928,7 +1933,7 @@ public:
explicit ExpressionSetDifference(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSetDifference, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1942,7 +1947,7 @@ public:
explicit ExpressionSetEquals(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetEquals>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void validateArguments(const ExpressionVector& args) const final;
@@ -1957,7 +1962,7 @@ public:
explicit ExpressionSetIntersection(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetIntersection>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1981,7 +1986,7 @@ public:
: ExpressionFixedArity<ExpressionSetIsSubset, 2>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() override;
- Value evaluate(const Document& root) const override;
+ Value evaluate(const Document& root, Variables* variables) const override;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -1998,7 +2003,7 @@ public:
explicit ExpressionSetUnion(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetUnion>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -2020,7 +2025,7 @@ public:
explicit ExpressionSize(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSize, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2034,7 +2039,7 @@ public:
explicit ExpressionReverseArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionReverseArray, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2048,7 +2053,7 @@ public:
explicit ExpressionSlice(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionSlice, 2, 3>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2062,7 +2067,7 @@ public:
explicit ExpressionIsArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIsArray, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2075,7 +2080,7 @@ public:
explicit ExpressionRound(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionRound, 1, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2088,7 +2093,7 @@ public:
explicit ExpressionSplit(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSplit, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2116,7 +2121,7 @@ public:
explicit ExpressionStrcasecmp(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrcasecmp, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2130,7 +2135,7 @@ public:
explicit ExpressionSubstrBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubstrBytes, 3>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2144,7 +2149,7 @@ public:
explicit ExpressionSubstrCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubstrCP, 3>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2158,7 +2163,7 @@ public:
explicit ExpressionStrLenBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrLenBytes, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2172,7 +2177,7 @@ public:
explicit ExpressionStrLenCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrLenCP, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2186,7 +2191,7 @@ public:
explicit ExpressionSubtract(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubtract, 2>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2207,7 +2212,7 @@ public:
_default(_children.back()),
_branches(std::move(branches)) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -2233,7 +2238,7 @@ public:
explicit ExpressionToLower(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionToLower, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2247,7 +2252,7 @@ public:
explicit ExpressionToUpper(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionToUpper, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2279,7 +2284,7 @@ public:
_input(_children[0]),
_characters(_children[1]) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -2337,7 +2342,7 @@ public:
const boost::intrusive_ptr<ExpressionContext>& expCtx,
BSONElement elem,
const VariablesParseState& vps);
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2351,7 +2356,7 @@ public:
explicit ExpressionType(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionType, 1>(expCtx) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
const char* getOpName() const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
@@ -2463,7 +2468,7 @@ public:
_inputs(std::move(inputs)),
_defaults(std::move(defaults)) {}
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -2499,7 +2504,7 @@ public:
BSONElement expr,
const VariablesParseState& vpsIn);
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
@@ -2567,7 +2572,7 @@ public:
* Validates the structure of input passed in 'inputExpr'. If valid, generates an initial
* execution state. This returned object can later be used for calling execute() or nextMatch().
*/
- RegexExecutionState buildInitialState(const Document& root) const;
+ RegexExecutionState buildInitialState(const Document& root, Variables* variables) const;
/**
* Checks if there is a match for the given input and pattern that are part of 'executionState'.
@@ -2652,7 +2657,7 @@ public:
BSONElement expr,
const VariablesParseState& vpsIn);
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
return visitor->visit(this);
@@ -2668,7 +2673,7 @@ public:
BSONElement expr,
const VariablesParseState& vpsIn);
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
return visitor->visit(this);
}
@@ -2683,7 +2688,7 @@ public:
BSONElement expr,
const VariablesParseState& vpsIn);
- Value evaluate(const Document& root) const final;
+ Value evaluate(const Document& root, Variables* variables) const final;
void acceptVisitor(ExpressionVisitor* visitor) final {
return visitor->visit(this);
diff --git a/src/mongo/db/pipeline/expression_convert_test.cpp b/src/mongo/db/pipeline/expression_convert_test.cpp
index b5f22579438..a0a5c2d4a64 100644
--- a/src/mongo/db/pipeline/expression_convert_test.cpp
+++ b/src/mongo/db/pipeline/expression_convert_test.cpp
@@ -157,7 +157,7 @@ TEST_F(ExpressionConvertTest, InvalidTypeNameFails) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document()),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document(), &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::BadValue);
@@ -177,7 +177,7 @@ TEST_F(ExpressionConvertTest, NonIntegralTypeFails) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document()),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document(), &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::FailedToParse);
@@ -200,7 +200,7 @@ TEST_F(ExpressionConvertTest, NonStringNonNumericalTypeFails) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document()),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(Document(), &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::FailedToParse);
@@ -223,7 +223,7 @@ TEST_F(ExpressionConvertTest, InvalidNumericTargetTypeFails) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate(Document()),
+ convertExp->evaluate(Document(), &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::FailedToParse);
@@ -246,7 +246,7 @@ TEST_F(ExpressionConvertTest, NegativeNumericTargetTypeFails) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate(Document()),
+ convertExp->evaluate(Document(), &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::FailedToParse);
@@ -304,7 +304,7 @@ TEST_F(ExpressionConvertTest, UnsupportedConversionShouldThrowUnlessOnErrorProvi
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(input),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(input, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -329,7 +329,8 @@ TEST_F(ExpressionConvertTest, UnsupportedConversionShouldThrowUnlessOnErrorProvi
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(input), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(input, &expCtx->variables), "X"_sd, BSONType::String);
}
}
@@ -346,9 +347,9 @@ TEST_F(ExpressionConvertTest, ConvertNullishInput) {
Document undefinedInput{{"path1", BSONUndefined}};
Document missingInput{{"path1", Value()}};
- ASSERT_VALUE_EQ(convertExp->evaluate(nullInput), Value(BSONNULL));
- ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput), Value(BSONNULL));
- ASSERT_VALUE_EQ(convertExp->evaluate(missingInput), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(nullInput, &expCtx->variables), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput, &expCtx->variables), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(missingInput, &expCtx->variables), Value(BSONNULL));
}
TEST_F(ExpressionConvertTest, ConvertNullishInputWithOnNull) {
@@ -368,9 +369,9 @@ TEST_F(ExpressionConvertTest, ConvertNullishInputWithOnNull) {
Document undefinedInput{{"path1", BSONUndefined}};
Document missingInput{{"path1", Value()}};
- ASSERT_VALUE_EQ(convertExp->evaluate(nullInput), Value("B)"_sd));
- ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput), Value("B)"_sd));
- ASSERT_VALUE_EQ(convertExp->evaluate(missingInput), Value("B)"_sd));
+ ASSERT_VALUE_EQ(convertExp->evaluate(nullInput, &expCtx->variables), Value("B)"_sd));
+ ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput, &expCtx->variables), Value("B)"_sd));
+ ASSERT_VALUE_EQ(convertExp->evaluate(missingInput, &expCtx->variables), Value("B)"_sd));
}
TEST_F(ExpressionConvertTest, NullishToReturnsNull) {
@@ -390,9 +391,9 @@ TEST_F(ExpressionConvertTest, NullishToReturnsNull) {
Document undefinedInput{{"path1", BSONUndefined}};
Document missingInput{{"path1", Value()}};
- ASSERT_VALUE_EQ(convertExp->evaluate(nullInput), Value(BSONNULL));
- ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput), Value(BSONNULL));
- ASSERT_VALUE_EQ(convertExp->evaluate(missingInput), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(nullInput, &expCtx->variables), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(undefinedInput, &expCtx->variables), Value(BSONNULL));
+ ASSERT_VALUE_EQ(convertExp->evaluate(missingInput, &expCtx->variables), Value(BSONNULL));
}
TEST_F(ExpressionConvertTest, NullInputOverridesNullTo) {
@@ -403,7 +404,8 @@ TEST_F(ExpressionConvertTest, NullInputOverridesNullTo) {
<< "X"));
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(Document{}), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(Document{}, &expCtx->variables), "X"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertOptimizesToExpressionConstant) {
@@ -444,20 +446,21 @@ TEST_F(ExpressionConvertTest, DoubleIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document doubleInput{{"path1", 2.4}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInput), 2.4, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleInput, &expCtx->variables), 2.4, BSONType::NumberDouble);
Document doubleNaN{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- auto result = convertExp->evaluate(doubleNaN);
+ auto result = convertExp->evaluate(doubleNaN, &expCtx->variables);
ASSERT(std::isnan(result.getDouble()));
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- result = convertExp->evaluate(doubleInfinity);
+ result = convertExp->evaluate(doubleInfinity, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT_GT(result.getDouble(), 0.0);
ASSERT(std::isinf(result.getDouble()));
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
- result = convertExp->evaluate(doubleNegativeInfinity);
+ result = convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT_LT(result.getDouble(), 0.0);
ASSERT(std::isinf(result.getDouble()));
@@ -473,10 +476,12 @@ TEST_F(ExpressionConvertTest, BoolIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueBoolInput{{"path1", true}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueBoolInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueBoolInput, &expCtx->variables), true, BSONType::Bool);
Document falseBoolInput{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseBoolInput), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseBoolInput, &expCtx->variables), false, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, StringIdentityConversion) {
@@ -490,7 +495,7 @@ TEST_F(ExpressionConvertTest, StringIdentityConversion) {
Document stringInput{{"path1", "More cowbell"_sd}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(stringInput), "More cowbell"_sd, BSONType::String);
+ convertExp->evaluate(stringInput, &expCtx->variables), "More cowbell"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ObjectIdIdentityConversion) {
@@ -503,8 +508,9 @@ TEST_F(ExpressionConvertTest, ObjectIdIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document oidInput{{"path1", OID("0123456789abcdef01234567")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(oidInput), OID("0123456789abcdef01234567"), BSONType::jstOID);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(oidInput, &expCtx->variables),
+ OID("0123456789abcdef01234567"),
+ BSONType::jstOID);
}
TEST_F(ExpressionConvertTest, DateIdentityConversion) {
@@ -517,7 +523,8 @@ TEST_F(ExpressionConvertTest, DateIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document dateInput{{"path1", Date_t{}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput), Date_t{}, BSONType::Date);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(dateInput, &expCtx->variables), Date_t{}, BSONType::Date);
}
TEST_F(ExpressionConvertTest, IntIdentityConversion) {
@@ -530,7 +537,8 @@ TEST_F(ExpressionConvertTest, IntIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document intInput{{"path1", int{123}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(intInput), int{123}, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(intInput, &expCtx->variables), int{123}, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, LongIdentityConversion) {
@@ -543,7 +551,8 @@ TEST_F(ExpressionConvertTest, LongIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document longInput{{"path1", 123LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(longInput), 123LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(longInput, &expCtx->variables), 123LL, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, DecimalIdentityConversion) {
@@ -556,22 +565,25 @@ TEST_F(ExpressionConvertTest, DecimalIdentityConversion) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document decimalInput{{"path1", Decimal128("2.4")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalInput), Decimal128("2.4"), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInput, &expCtx->variables),
+ Decimal128("2.4"),
+ BSONType::NumberDecimal);
Document decimalNaN{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNaN), Decimal128::kPositiveNaN, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalNaN, &expCtx->variables),
+ Decimal128::kPositiveNaN,
+ BSONType::NumberDecimal);
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity),
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity, &expCtx->variables),
Decimal128::kPositiveInfinity,
BSONType::NumberDecimal);
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalNegativeInfinity),
- Decimal128::kNegativeInfinity,
- BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
+ Decimal128::kNegativeInfinity,
+ BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertDateToBool) {
@@ -585,7 +597,8 @@ TEST_F(ExpressionConvertTest, ConvertDateToBool) {
// All date inputs evaluate as true.
Document dateInput{{"path1", Date_t{}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(dateInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertIntToBool) {
@@ -598,10 +611,12 @@ TEST_F(ExpressionConvertTest, ConvertIntToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueIntInput{{"path1", int{1}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueIntInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueIntInput, &expCtx->variables), true, BSONType::Bool);
Document falseIntInput{{"path1", int{0}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseIntInput), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseIntInput, &expCtx->variables), false, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertLongToBool) {
@@ -614,10 +629,12 @@ TEST_F(ExpressionConvertTest, ConvertLongToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueLongInput{{"path1", -1LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueLongInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueLongInput, &expCtx->variables), true, BSONType::Bool);
Document falseLongInput{{"path1", 0LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseLongInput), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseLongInput, &expCtx->variables), false, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertDoubleToBool) {
@@ -630,20 +647,24 @@ TEST_F(ExpressionConvertTest, ConvertDoubleToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueDoubleInput{{"path1", 2.4}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueDoubleInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueDoubleInput, &expCtx->variables), true, BSONType::Bool);
Document falseDoubleInput{{"path1", -0.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseDoubleInput), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseDoubleInput, &expCtx->variables), false, BSONType::Bool);
Document doubleNaN{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleNaN), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleNaN, &expCtx->variables), true, BSONType::Bool);
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleInfinity, &expCtx->variables), true, BSONType::Bool);
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNegativeInfinity), true, BSONType::Bool);
+ convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertDecimalToBool) {
@@ -656,29 +677,36 @@ TEST_F(ExpressionConvertTest, ConvertDecimalToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueDecimalInput{{"path1", Decimal128(5)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueDecimalInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueDecimalInput, &expCtx->variables), true, BSONType::Bool);
Document falseDecimalInput{{"path1", Decimal128(0)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseDecimalInput), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseDecimalInput, &expCtx->variables), false, BSONType::Bool);
Document preciseZero{{"path1", Decimal128("0.00")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(preciseZero), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(preciseZero, &expCtx->variables), false, BSONType::Bool);
Document negativeZero{{"path1", Decimal128("-0.00")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeZero), false, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(negativeZero, &expCtx->variables), false, BSONType::Bool);
Document decimalNaN{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalNaN), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalNaN, &expCtx->variables), true, BSONType::Bool);
Document decimalNegativeNaN{{"path1", Decimal128::kNegativeNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalNegativeNaN), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalNegativeNaN, &expCtx->variables), true, BSONType::Bool);
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalInfinity, &expCtx->variables), true, BSONType::Bool);
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeInfinity), true, BSONType::Bool);
+ convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertStringToBool) {
@@ -691,10 +719,12 @@ TEST_F(ExpressionConvertTest, ConvertStringToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document stringInput{{"path1", "str"_sd}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(stringInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(stringInput, &expCtx->variables), true, BSONType::Bool);
Document emptyStringInput{{"path1", ""_sd}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(emptyStringInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(emptyStringInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertObjectIdToBool) {
@@ -707,7 +737,8 @@ TEST_F(ExpressionConvertTest, ConvertObjectIdToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document oidInput{{"path1", OID("59E8A8D8FEDCBA9876543210")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(oidInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(oidInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertMinKeyToBool) {
@@ -720,7 +751,8 @@ TEST_F(ExpressionConvertTest, ConvertMinKeyToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document minKeyInput{{"path1", MINKEY}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minKeyInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minKeyInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertObjectToBool) {
@@ -733,7 +765,8 @@ TEST_F(ExpressionConvertTest, ConvertObjectToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document objectInput{{"path1", Document{{"foo", 1}}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(objectInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(objectInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertArrayToBool) {
@@ -746,7 +779,8 @@ TEST_F(ExpressionConvertTest, ConvertArrayToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document arrayInput{{"path1", BSON_ARRAY(1)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(arrayInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(arrayInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertBinDataToBool) {
@@ -760,7 +794,8 @@ TEST_F(ExpressionConvertTest, ConvertBinDataToBool) {
char data[] = "(^_^)";
Document binInput{{"path1", BSONBinData(data, sizeof(data), BinDataType::BinDataGeneral)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(binInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(binInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertRegexToBool) {
@@ -773,7 +808,8 @@ TEST_F(ExpressionConvertTest, ConvertRegexToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document regexInput{{"path1", BSONRegEx("ab*a"_sd)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(regexInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(regexInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertDBRefToBool) {
@@ -786,7 +822,8 @@ TEST_F(ExpressionConvertTest, ConvertDBRefToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document refInput{{"path1", BSONDBRef("db.coll"_sd, OID("aaaaaaaaaaaaaaaaaaaaaaaa"))}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(refInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(refInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertCodeToBool) {
@@ -799,7 +836,8 @@ TEST_F(ExpressionConvertTest, ConvertCodeToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document codeInput{{"path1", BSONCode("print('Hello world!');"_sd)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(codeInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(codeInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertSymbolToBool) {
@@ -812,7 +850,8 @@ TEST_F(ExpressionConvertTest, ConvertSymbolToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document symbolInput{{"path1", BSONSymbol("print"_sd)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(symbolInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(symbolInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertCodeWScopeToBool) {
@@ -826,7 +865,8 @@ TEST_F(ExpressionConvertTest, ConvertCodeWScopeToBool) {
Document codeWScopeInput{
{"path1", BSONCodeWScope("print('Hello again, world!')"_sd, BSONObj())}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(codeWScopeInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(codeWScopeInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertTimestampToBool) {
@@ -839,7 +879,8 @@ TEST_F(ExpressionConvertTest, ConvertTimestampToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document timestampInput{{"path1", Timestamp()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(timestampInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(timestampInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertMaxKeyToBool) {
@@ -852,7 +893,8 @@ TEST_F(ExpressionConvertTest, ConvertMaxKeyToBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document maxKeyInput{{"path1", MAXKEY}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxKeyInput), true, BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxKeyInput, &expCtx->variables), true, BSONType::Bool);
}
TEST_F(ExpressionConvertTest, ConvertNumericToDouble) {
@@ -865,39 +907,43 @@ TEST_F(ExpressionConvertTest, ConvertNumericToDouble) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document intInput{{"path1", int{1}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(intInput), 1.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(intInput, &expCtx->variables), 1.0, BSONType::NumberDouble);
Document longInput{{"path1", 0xf00000000LL}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(longInput), 64424509440.0, BSONType::NumberDouble);
+ convertExp->evaluate(longInput, &expCtx->variables), 64424509440.0, BSONType::NumberDouble);
Document decimalInput{{"path1", Decimal128("5.5")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInput), 5.5, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalInput, &expCtx->variables), 5.5, BSONType::NumberDouble);
Document boolFalse{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolFalse), 0.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolFalse, &expCtx->variables), 0.0, BSONType::NumberDouble);
Document boolTrue{{"path1", true}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolTrue), 1.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolTrue, &expCtx->variables), 1.0, BSONType::NumberDouble);
Document decimalNaN{{"path1", Decimal128::kPositiveNaN}};
- auto result = convertExp->evaluate(decimalNaN);
+ auto result = convertExp->evaluate(decimalNaN, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT(std::isnan(result.getDouble()));
Document decimalNegativeNaN{{"path1", Decimal128::kNegativeNaN}};
- result = convertExp->evaluate(decimalNegativeNaN);
+ result = convertExp->evaluate(decimalNegativeNaN, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT(std::isnan(result.getDouble()));
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- result = convertExp->evaluate(decimalInfinity);
+ result = convertExp->evaluate(decimalInfinity, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT_GT(result.getDouble(), 0.0);
ASSERT(std::isinf(result.getDouble()));
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
- result = convertExp->evaluate(decimalNegativeInfinity);
+ result = convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::NumberDouble);
ASSERT_LT(result.getDouble(), 0.0);
ASSERT(std::isinf(result.getDouble()));
@@ -905,12 +951,12 @@ TEST_F(ExpressionConvertTest, ConvertNumericToDouble) {
// Note that the least significant bits get lost, because the significand of a double is not
// wide enough for the original long long value in its entirety.
Document largeLongInput{{"path1", 0xf0000000000000fLL}};
- result = convertExp->evaluate(largeLongInput);
+ result = convertExp->evaluate(largeLongInput, &expCtx->variables);
ASSERT_EQ(static_cast<long long>(result.getDouble()), 0xf00000000000000LL);
// Again, some precision is lost in the conversion from Decimal128 to double.
Document preciseDecimalInput{{"path1", Decimal128("1.125000000000000000005")}};
- result = convertExp->evaluate(preciseDecimalInput);
+ result = convertExp->evaluate(preciseDecimalInput, &expCtx->variables);
ASSERT_EQ(result.getDouble(), 1.125);
}
@@ -924,13 +970,15 @@ TEST_F(ExpressionConvertTest, ConvertDateToDouble) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document dateInput{{"path1", Date_t::fromMillisSinceEpoch(123)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput), 123.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(dateInput, &expCtx->variables), 123.0, BSONType::NumberDouble);
// Note that the least significant bits get lost, because the significand of a double is not
// wide enough for the original 64-bit Date_t value in its entirety.
Document largeDateInput{{"path1", Date_t::fromMillisSinceEpoch(0xf0000000000000fLL)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(largeDateInput), 0xf00000000000000LL, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(largeDateInput, &expCtx->variables),
+ 0xf00000000000000LL,
+ BSONType::NumberDouble);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToDouble) {
@@ -943,7 +991,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToDouble) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document overflowInput{{"path1", Decimal128("1e309")}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -952,7 +1000,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToDouble) {
});
Document negativeOverflowInput{{"path1", Decimal128("-1e309")}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -973,11 +1021,12 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToDoubleWithOnError) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document overflowInput{{"path1", Decimal128("1e309")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document negativeOverflowInput{{"path1", Decimal128("-1e309")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertNumericToDecimal) {
@@ -991,44 +1040,48 @@ TEST_F(ExpressionConvertTest, ConvertNumericToDecimal) {
Document intInput{{"path1", int{1}}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(intInput), Decimal128(1), BSONType::NumberDecimal);
+ convertExp->evaluate(intInput, &expCtx->variables), Decimal128(1), BSONType::NumberDecimal);
Document longInput{{"path1", 0xf00000000LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(longInput),
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(longInput, &expCtx->variables),
Decimal128(std::int64_t{0xf00000000LL}),
BSONType::NumberDecimal);
Document doubleInput{{"path1", 0.1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleInput), Decimal128("0.1"), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInput, &expCtx->variables),
+ Decimal128("0.1"),
+ BSONType::NumberDecimal);
Document boolFalse{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(boolFalse), Decimal128(0), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolFalse, &expCtx->variables),
+ Decimal128(0),
+ BSONType::NumberDecimal);
Document boolTrue{{"path1", true}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(boolTrue), Decimal128(1), BSONType::NumberDecimal);
+ convertExp->evaluate(boolTrue, &expCtx->variables), Decimal128(1), BSONType::NumberDecimal);
Document doubleNaN{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNaN), Decimal128::kPositiveNaN, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleNaN, &expCtx->variables),
+ Decimal128::kPositiveNaN,
+ BSONType::NumberDecimal);
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity),
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity, &expCtx->variables),
Decimal128::kPositiveInfinity,
BSONType::NumberDecimal);
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleNegativeInfinity),
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables),
Decimal128::kNegativeInfinity,
BSONType::NumberDecimal);
// Unlike the similar conversion in ConvertNumericToDouble, there is more than enough precision
// to store the exact orignal value in a Decimal128.
Document largeLongInput{{"path1", 0xf0000000000000fLL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(largeLongInput), 0xf0000000000000fLL, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(largeLongInput, &expCtx->variables),
+ 0xf0000000000000fLL,
+ BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertDateToDecimal) {
@@ -1041,12 +1094,14 @@ TEST_F(ExpressionConvertTest, ConvertDateToDecimal) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document dateInput{{"path1", Date_t::fromMillisSinceEpoch(123)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(dateInput), Decimal128(123), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput, &expCtx->variables),
+ Decimal128(123),
+ BSONType::NumberDecimal);
Document largeDateInput{{"path1", Date_t::fromMillisSinceEpoch(0xf0000000000000fLL)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(largeDateInput), 0xf0000000000000fLL, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(largeDateInput, &expCtx->variables),
+ 0xf0000000000000fLL,
+ BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertDoubleToInt) {
@@ -1059,28 +1114,35 @@ TEST_F(ExpressionConvertTest, ConvertDoubleToInt) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", 1.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1, BSONType::NumberInt);
// Conversions to int should always truncate the fraction (i.e., round towards 0).
Document nonIntegerInput1{{"path1", 2.1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput1), 2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput1, &expCtx->variables), 2, BSONType::NumberInt);
Document nonIntegerInput2{{"path1", 2.9}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput2), 2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput2, &expCtx->variables), 2, BSONType::NumberInt);
Document nonIntegerInput3{{"path1", -2.1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput3), -2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput3, &expCtx->variables), -2, BSONType::NumberInt);
Document nonIntegerInput4{{"path1", -2.9}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput4), -2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput4, &expCtx->variables), -2, BSONType::NumberInt);
int maxInt = std::numeric_limits<int>::max();
Document maxInput{{"path1", static_cast<double>(maxInt)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput), maxInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxInput, &expCtx->variables), maxInt, BSONType::NumberInt);
int minInt = std::numeric_limits<int>::lowest();
Document minInput{{"path1", static_cast<double>(minInt)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput), minInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minInput, &expCtx->variables), minInt, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
@@ -1096,7 +1158,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
double overflowInt =
std::nextafter(static_cast<double>(maxInt), std::numeric_limits<double>::max());
Document overflowInput{{"path1", overflowInt}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1108,7 +1170,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
double negativeOverflowInt =
std::nextafter(static_cast<double>(minInt), std::numeric_limits<double>::lowest());
Document negativeOverflowInput{{"path1", negativeOverflowInt}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1117,7 +1179,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
});
Document nanInput{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1126,7 +1188,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
});
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1136,7 +1198,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToInt) {
});
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1161,24 +1223,27 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToIntWithOnError) {
double overflowInt =
std::nextafter(static_cast<double>(maxInt), std::numeric_limits<double>::max());
Document overflowInput{{"path1", overflowInt}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
int minInt = std::numeric_limits<int>::lowest();
double negativeOverflowInt =
std::nextafter(static_cast<double>(minInt), std::numeric_limits<double>::lowest());
Document negativeOverflowInput{{"path1", negativeOverflowInt}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document nanInput{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables), "X"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertDoubleToLong) {
@@ -1191,34 +1256,39 @@ TEST_F(ExpressionConvertTest, ConvertDoubleToLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", 1.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1, BSONType::NumberLong);
// Conversions to int should always truncate the fraction (i.e., round towards 0).
Document nonIntegerInput1{{"path1", 2.1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput1), 2, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput1, &expCtx->variables), 2, BSONType::NumberLong);
Document nonIntegerInput2{{"path1", 2.9}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput2), 2, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput2, &expCtx->variables), 2, BSONType::NumberLong);
Document nonIntegerInput3{{"path1", -2.1}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(nonIntegerInput3), -2, BSONType::NumberLong);
+ convertExp->evaluate(nonIntegerInput3, &expCtx->variables), -2, BSONType::NumberLong);
Document nonIntegerInput4{{"path1", -2.9}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(nonIntegerInput4), -2, BSONType::NumberLong);
+ convertExp->evaluate(nonIntegerInput4, &expCtx->variables), -2, BSONType::NumberLong);
// maxVal is the highest double value that will not overflow long long.
double maxVal = std::nextafter(BSONElement::kLongLongMaxPlusOneAsDouble, 0.0);
Document maxInput{{"path1", maxVal}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(maxInput), static_cast<long long>(maxVal), BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput, &expCtx->variables),
+ static_cast<long long>(maxVal),
+ BSONType::NumberLong);
// minVal is the lowest double value that will not overflow long long.
double minVal = static_cast<double>(std::numeric_limits<long long>::lowest());
Document minInput{{"path1", minVal}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(minInput), static_cast<long long>(minVal), BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput, &expCtx->variables),
+ static_cast<long long>(minVal),
+ BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
@@ -1232,7 +1302,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
double overflowLong = BSONElement::kLongLongMaxPlusOneAsDouble;
Document overflowInput{{"path1", overflowLong}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1244,7 +1314,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
double negativeOverflowLong =
std::nextafter(static_cast<double>(minLong), std::numeric_limits<double>::lowest());
Document negativeOverflowInput{{"path1", negativeOverflowLong}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1253,7 +1323,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
});
Document nanInput{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1262,7 +1332,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
});
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1272,7 +1342,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLong) {
});
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1295,24 +1365,27 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDoubleToLongWithOnError) {
double overflowLong = BSONElement::kLongLongMaxPlusOneAsDouble;
Document overflowInput{{"path1", overflowLong}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
double minLong = static_cast<double>(std::numeric_limits<long long>::lowest());
double negativeOverflowLong =
std::nextafter(static_cast<double>(minLong), std::numeric_limits<double>::lowest());
Document negativeOverflowInput{{"path1", negativeOverflowLong}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document nanInput{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables), "X"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertDecimalToInt) {
@@ -1325,28 +1398,35 @@ TEST_F(ExpressionConvertTest, ConvertDecimalToInt) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", Decimal128("1.0")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1, BSONType::NumberInt);
// Conversions to int should always truncate the fraction (i.e., round towards 0).
Document nonIntegerInput1{{"path1", Decimal128("2.1")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput1), 2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput1, &expCtx->variables), 2, BSONType::NumberInt);
Document nonIntegerInput2{{"path1", Decimal128("2.9")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput2), 2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput2, &expCtx->variables), 2, BSONType::NumberInt);
Document nonIntegerInput3{{"path1", Decimal128("-2.1")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput3), -2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput3, &expCtx->variables), -2, BSONType::NumberInt);
Document nonIntegerInput4{{"path1", Decimal128("-2.9")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput3), -2, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput3, &expCtx->variables), -2, BSONType::NumberInt);
int maxInt = std::numeric_limits<int>::max();
Document maxInput{{"path1", Decimal128(maxInt)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput), maxInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxInput, &expCtx->variables), maxInt, BSONType::NumberInt);
int minInt = std::numeric_limits<int>::min();
Document minInput{{"path1", Decimal128(minInt)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput), minInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minInput, &expCtx->variables), minInt, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
@@ -1360,7 +1440,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
int maxInt = std::numeric_limits<int>::max();
Document overflowInput{{"path1", Decimal128(maxInt).add(Decimal128(1))}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1370,7 +1450,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
int minInt = std::numeric_limits<int>::lowest();
Document negativeOverflowInput{{"path1", Decimal128(minInt).subtract(Decimal128(1))}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1379,7 +1459,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
});
Document nanInput{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1388,7 +1468,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
});
Document negativeNaNInput{{"path1", Decimal128::kNegativeNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeNaNInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeNaNInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1397,7 +1477,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
});
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1407,7 +1487,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToInt) {
});
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1430,26 +1510,31 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToIntWithOnError) {
int maxInt = std::numeric_limits<int>::max();
Document overflowInput{{"path1", Decimal128(maxInt).add(Decimal128(1))}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
int minInt = std::numeric_limits<int>::lowest();
Document negativeOverflowInput{{"path1", Decimal128(minInt).subtract(Decimal128(1))}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document nanInput{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "X"_sd, BSONType::String);
Document negativeNaNInput{{"path1", Decimal128::kNegativeNaN}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeNaNInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeNaNInput, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
+ "X"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertDecimalToLong) {
@@ -1462,30 +1547,35 @@ TEST_F(ExpressionConvertTest, ConvertDecimalToLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", Decimal128("1.0")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1, BSONType::NumberLong);
// Conversions to long should always truncate the fraction (i.e., round towards 0).
Document nonIntegerInput1{{"path1", Decimal128("2.1")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput1), 2, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput1, &expCtx->variables), 2, BSONType::NumberLong);
Document nonIntegerInput2{{"path1", Decimal128("2.9")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nonIntegerInput2), 2, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nonIntegerInput2, &expCtx->variables), 2, BSONType::NumberLong);
Document nonIntegerInput3{{"path1", Decimal128("-2.1")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(nonIntegerInput3), -2, BSONType::NumberLong);
+ convertExp->evaluate(nonIntegerInput3, &expCtx->variables), -2, BSONType::NumberLong);
Document nonIntegerInput4{{"path1", Decimal128("-2.9")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(nonIntegerInput4), -2, BSONType::NumberLong);
+ convertExp->evaluate(nonIntegerInput4, &expCtx->variables), -2, BSONType::NumberLong);
long long maxVal = std::numeric_limits<long long>::max();
Document maxInput{{"path1", Decimal128(std::int64_t{maxVal})}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput), maxVal, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxInput, &expCtx->variables), maxVal, BSONType::NumberLong);
long long minVal = std::numeric_limits<long long>::min();
Document minInput{{"path1", Decimal128(std::int64_t{minVal})}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput), minVal, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minInput, &expCtx->variables), minVal, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
@@ -1499,7 +1589,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
long long maxVal = std::numeric_limits<long long>::max();
Document overflowInput{{"path1", Decimal128(std::int64_t{maxVal}).add(Decimal128(1))}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1510,7 +1600,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
long long minVal = std::numeric_limits<long long>::lowest();
Document negativeOverflowInput{
{"path1", Decimal128(std::int64_t{minVal}).subtract(Decimal128(1))}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1519,7 +1609,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
});
Document nanInput{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(nanInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1528,7 +1618,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
});
Document negativeNaNInput{{"path1", Decimal128::kNegativeNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeNaNInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeNaNInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1537,7 +1627,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
});
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1547,7 +1637,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLong) {
});
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1570,27 +1660,32 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsDecimalToLongWithOnError) {
long long maxVal = std::numeric_limits<long long>::max();
Document overflowInput{{"path1", Decimal128(std::int64_t{maxVal}).add(Decimal128(1))}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
long long minVal = std::numeric_limits<long long>::lowest();
Document negativeOverflowInput{
{"path1", Decimal128(std::int64_t{minVal}).subtract(Decimal128(1))}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document nanInput{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "X"_sd, BSONType::String);
Document negativeNaNInput{{"path1", Decimal128::kNegativeNaN}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeNaNInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeNaNInput, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
+ "X"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertDateToLong) {
@@ -1603,7 +1698,8 @@ TEST_F(ExpressionConvertTest, ConvertDateToLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document dateInput{{"path1", Date_t::fromMillisSinceEpoch(123LL)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput), 123LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(dateInput, &expCtx->variables), 123LL, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertIntToLong) {
@@ -1616,15 +1712,18 @@ TEST_F(ExpressionConvertTest, ConvertIntToLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", 1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1LL, BSONType::NumberLong);
int maxInt = std::numeric_limits<int>::max();
Document maxInput{{"path1", maxInt}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput), maxInt, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxInput, &expCtx->variables), maxInt, BSONType::NumberLong);
int minInt = std::numeric_limits<int>::min();
Document minInput{{"path1", minInt}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput), minInt, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minInput, &expCtx->variables), minInt, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertLongToInt) {
@@ -1637,15 +1736,18 @@ TEST_F(ExpressionConvertTest, ConvertLongToInt) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document simpleInput{{"path1", 1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput), 1, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(simpleInput, &expCtx->variables), 1, BSONType::NumberInt);
long long maxInt = std::numeric_limits<int>::max();
Document maxInput{{"path1", maxInt}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(maxInput), maxInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(maxInput, &expCtx->variables), maxInt, BSONType::NumberInt);
long long minInt = std::numeric_limits<int>::min();
Document minInput{{"path1", minInt}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(minInput), minInt, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(minInput, &expCtx->variables), minInt, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, ConvertOutOfBoundsLongToInt) {
@@ -1659,7 +1761,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsLongToInt) {
long long maxInt = std::numeric_limits<int>::max();
Document overflowInput{{"path1", maxInt + 1}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(overflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1669,7 +1771,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsLongToInt) {
long long minInt = std::numeric_limits<int>::min();
Document negativeOverflowInput{{"path1", minInt - 1}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(negativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1691,12 +1793,13 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsLongToIntWithOnError) {
long long maxInt = std::numeric_limits<int>::max();
Document overflowInput{{"path1", maxInt + 1}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(overflowInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(overflowInput, &expCtx->variables), "X"_sd, BSONType::String);
long long minInt = std::numeric_limits<int>::min();
Document negativeOverflowInput{{"path1", minInt - 1}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(negativeOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertBoolToInt) {
@@ -1709,10 +1812,12 @@ TEST_F(ExpressionConvertTest, ConvertBoolToInt) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document boolFalse{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolFalse), 0, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolFalse, &expCtx->variables), 0, BSONType::NumberInt);
Document boolTrue{{"path1", true}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolTrue), 1, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolTrue, &expCtx->variables), 1, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, ConvertBoolToLong) {
@@ -1725,10 +1830,12 @@ TEST_F(ExpressionConvertTest, ConvertBoolToLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document boolFalse{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolFalse), 0LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolFalse, &expCtx->variables), 0LL, BSONType::NumberLong);
Document boolTrue{{"path1", true}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(boolTrue), 1LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(boolTrue, &expCtx->variables), 1LL, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertNumberToDate) {
@@ -1741,23 +1848,25 @@ TEST_F(ExpressionConvertTest, ConvertNumberToDate) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document longInput{{"path1", 0LL}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(longInput).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(longInput, &expCtx->variables).getDate()),
"1970-01-01T00:00:00.000Z");
Document doubleInput{{"path1", 431568000000.0}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(doubleInput).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(doubleInput, &expCtx->variables).getDate()),
"1983-09-05T00:00:00.000Z");
Document doubleInputWithFraction{{"path1", 431568000000.987}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(doubleInputWithFraction).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(
+ convertExp->evaluate(doubleInputWithFraction, &expCtx->variables).getDate()),
"1983-09-05T00:00:00.000Z");
Document decimalInput{{"path1", Decimal128("872835240000")}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(decimalInput).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(decimalInput, &expCtx->variables).getDate()),
"1997-08-29T06:14:00.000Z");
Document decimalInputWithFraction{{"path1", Decimal128("872835240000.987")}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(decimalInputWithFraction).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(
+ convertExp->evaluate(decimalInputWithFraction, &expCtx->variables).getDate()),
"1997-08-29T06:14:00.000Z");
}
@@ -1771,7 +1880,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document doubleOverflowInput{{"path1", 1.0e100}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1780,7 +1889,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document doubleNegativeOverflowInput{{"path1", -1.0e100}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1789,7 +1898,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document doubleNaN{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNaN),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNaN, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1799,7 +1908,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1809,7 +1918,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1819,7 +1928,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalOverflowInput{{"path1", Decimal128("1.0e100")}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1828,7 +1937,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalNegativeOverflowInput{{"path1", Decimal128("1.0e100")}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeOverflowInput),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeOverflowInput, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1837,7 +1946,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalNaN{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNaN),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNaN, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1847,7 +1956,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalNegativeNaN{{"path1", Decimal128::kNegativeNaN}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeNaN),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeNaN, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1857,7 +1966,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1867,7 +1976,7 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDate) {
});
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity),
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
AssertionException,
[](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
@@ -1890,47 +1999,58 @@ TEST_F(ExpressionConvertTest, ConvertOutOfBoundsNumberToDateWithOnError) {
// Int is explicitly disallowed for date conversions. Clients must use 64-bit long instead.
Document intInput{{"path1", int{0}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(intInput), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(intInput, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleOverflowInput{{"path1", 1.0e100}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(doubleOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleNegativeOverflowInput{{"path1", -1.0e100}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNegativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(doubleNegativeOverflowInput, &expCtx->variables),
+ "X"_sd,
+ BSONType::String);
Document doubleNaN{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleNaN), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleNaN, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleInfinity{{"path1", std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(doubleInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(doubleInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document doubleNegativeInfinity{{"path1", -std::numeric_limits<double>::infinity()}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(doubleNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(doubleNegativeInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalOverflowInput{{"path1", Decimal128("1.0e100")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalOverflowInput, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalNegativeOverflowInput{{"path1", Decimal128("1.0e100")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeOverflowInput), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalNegativeOverflowInput, &expCtx->variables),
+ "X"_sd,
+ BSONType::String);
Document decimalNaN{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalNaN), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalNaN, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalNegativeNaN{{"path1", Decimal128::kNegativeNaN}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeNaN), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalNegativeNaN, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalInfinity{{"path1", Decimal128::kPositiveInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(decimalInfinity), "X"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(decimalInfinity, &expCtx->variables), "X"_sd, BSONType::String);
Document decimalNegativeInfinity{{"path1", Decimal128::kNegativeInfinity}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(decimalNegativeInfinity), "X"_sd, BSONType::String);
+ convertExp->evaluate(decimalNegativeInfinity, &expCtx->variables),
+ "X"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertObjectIdToDate) {
@@ -1944,7 +2064,7 @@ TEST_F(ExpressionConvertTest, ConvertObjectIdToDate) {
Document oidInput{{"path1", OID("59E8A8D8FEDCBA9876543210")}};
- ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(oidInput).getDate()),
+ ASSERT_EQ(dateToISOStringUTC(convertExp->evaluate(oidInput, &expCtx->variables).getDate()),
"2017-10-19T13:30:00.000Z");
}
@@ -1953,11 +2073,13 @@ TEST_F(ExpressionConvertTest, ConvertStringToInt) {
auto spec = fromjson("{$convert: {input: '5', to: 'int'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5, BSONType::NumberInt);
spec = fromjson("{$convert: {input: '" + std::to_string(kIntMax) + "', to: 'int'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), kIntMax, BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), kIntMax, BSONType::NumberInt);
}
TEST_F(ExpressionConvertTest, ConvertStringToIntOverflow) {
@@ -1965,19 +2087,21 @@ TEST_F(ExpressionConvertTest, ConvertStringToIntOverflow) {
auto spec = fromjson("{$convert: {input: '" + std::to_string(kIntMax + 1) + "', to: 'int'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
+ });
spec = fromjson("{$convert: {input: '" + std::to_string(kIntMin - 1) + "', to: 'int'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToIntOverflowWithOnError) {
@@ -1987,12 +2111,14 @@ TEST_F(ExpressionConvertTest, ConvertStringToIntOverflowWithOnError) {
auto spec = fromjson("{$convert: {input: '" + std::to_string(kIntMax + 1) +
"', to: 'int', onError: '" + onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '" + std::to_string(kIntMin - 1) +
"', to: 'int', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertStringToLong) {
@@ -2000,11 +2126,13 @@ TEST_F(ExpressionConvertTest, ConvertStringToLong) {
auto spec = fromjson("{$convert: {input: '5', to: 'long'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5LL, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5LL, BSONType::NumberLong);
spec = fromjson("{$convert: {input: '" + std::to_string(kLongMax) + "', to: 'long'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), kLongMax, BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), kLongMax, BSONType::NumberLong);
}
TEST_F(ExpressionConvertTest, ConvertStringToLongOverflow) {
@@ -2015,22 +2143,24 @@ TEST_F(ExpressionConvertTest, ConvertStringToLongOverflow) {
auto spec = fromjson("{$convert: {input: '" + longMaxPlusOneAsString + "', to: 'long'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
+ });
auto longMinMinusOneAsString = std::to_string(kLongNegativeOverflow);
longMinMinusOneAsString = longMinMinusOneAsString.substr(0, longMinMinusOneAsString.find('.'));
spec = fromjson("{$convert: {input: '" + longMinMinusOneAsString + "', to: 'long'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Overflow");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToLongFailsForFloats) {
@@ -2038,19 +2168,21 @@ TEST_F(ExpressionConvertTest, ConvertStringToLongFailsForFloats) {
auto spec = fromjson("{$convert: {input: '5.5', to: 'long'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Bad digit \".\"");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Bad digit \".\"");
+ });
spec = fromjson("{$convert: {input: '5.0', to: 'long'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Bad digit \".\"");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Bad digit \".\"");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToLongWithOnError) {
@@ -2063,7 +2195,8 @@ TEST_F(ExpressionConvertTest, ConvertStringToLongWithOnError) {
auto spec = fromjson("{$convert: {input: '" + longMaxPlusOneAsString +
"', to: 'long', onError: '" + onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
auto longMinMinusOneAsString = std::to_string(kLongNegativeOverflow);
longMinMinusOneAsString = longMinMinusOneAsString.substr(0, longMinMinusOneAsString.find('.'));
@@ -2071,15 +2204,18 @@ TEST_F(ExpressionConvertTest, ConvertStringToLongWithOnError) {
spec = fromjson("{$convert: {input: '" + longMinMinusOneAsString + "', to: 'long', onError: '" +
onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '5.5', to: 'long', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '5.0', to: 'long', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertStringToDouble) {
@@ -2087,23 +2223,28 @@ TEST_F(ExpressionConvertTest, ConvertStringToDouble) {
auto spec = fromjson("{$convert: {input: '5', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5.0, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '5.5', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5.5, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5.5, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '.5', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 0.5, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 0.5, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '+5', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5.0, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5.0, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '+5.0e42', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5.0e42, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5.0e42, BSONType::NumberDouble);
}
TEST_F(ExpressionConvertTest, ConvertStringToDoubleWithPrecisionLoss) {
@@ -2113,12 +2254,14 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleWithPrecisionLoss) {
// wide enough for the given input string in its entirety.
auto spec = fromjson("{$convert: {input: '10000000000000000001', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 1e19, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 1e19, BSONType::NumberDouble);
// Again, some precision is lost in the conversion to double.
spec = fromjson("{$convert: {input: '1.125000000000000000005', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 1.125, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 1.125, BSONType::NumberDouble);
}
TEST_F(ExpressionConvertTest, ConvertStringToDoubleFailsForInvalidFloats) {
@@ -2126,19 +2269,23 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleFailsForInvalidFloats) {
auto spec = fromjson("{$convert: {input: '.5.', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Did not consume whole number");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Did not consume whole number");
+ });
spec = fromjson("{$convert: {input: '5.5f', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Did not consume whole number");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Did not consume whole number");
+ });
}
TEST_F(ExpressionConvertTest, ConvertInfinityStringsToDouble) {
@@ -2147,39 +2294,48 @@ TEST_F(ExpressionConvertTest, ConvertInfinityStringsToDouble) {
auto spec = fromjson("{$convert: {input: 'Infinity', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: 'INF', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: 'infinity', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '+InFiNiTy', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '-Infinity', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), -infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), -infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '-INF', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), -infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), -infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '-InFiNiTy', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), -infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), -infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '-inf', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), -infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), -infValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: '-infinity', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), -infValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), -infValue, BSONType::NumberDouble);
}
TEST_F(ExpressionConvertTest, ConvertZeroStringsToDouble) {
@@ -2187,25 +2343,25 @@ TEST_F(ExpressionConvertTest, ConvertZeroStringsToDouble) {
auto spec = fromjson("{$convert: {input: '-0', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({});
+ auto result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDouble);
ASSERT_TRUE(std::signbit(result.getDouble()));
spec = fromjson("{$convert: {input: '-0.0', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDouble);
ASSERT_TRUE(std::signbit(result.getDouble()));
spec = fromjson("{$convert: {input: '+0', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDouble);
ASSERT_FALSE(std::signbit(result.getDouble()));
spec = fromjson("{$convert: {input: '+0.0', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDouble);
ASSERT_FALSE(std::signbit(result.getDouble()));
}
@@ -2216,28 +2372,29 @@ TEST_F(ExpressionConvertTest, ConvertNanStringsToDouble) {
auto spec = fromjson("{$convert: {input: 'nan', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({});
+ auto result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_TRUE(std::isnan(result.getDouble()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), nanValue, BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), nanValue, BSONType::NumberDouble);
spec = fromjson("{$convert: {input: 'Nan', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_TRUE(std::isnan(result.getDouble()));
spec = fromjson("{$convert: {input: 'NaN', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_TRUE(std::isnan(result.getDouble()));
spec = fromjson("{$convert: {input: '-NAN', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_TRUE(std::isnan(result.getDouble()));
spec = fromjson("{$convert: {input: '+NaN', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_TRUE(std::isnan(result.getDouble()));
}
@@ -2246,20 +2403,22 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleOverflow) {
auto spec = fromjson("{$convert: {input: '" + kDoubleOverflow.toString() + "', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Out of range");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Out of range");
+ });
spec =
fromjson("{$convert: {input: '" + kDoubleNegativeOverflow.toString() + "', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Out of range");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(), "Out of range");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToDoubleUnderflow) {
@@ -2268,7 +2427,9 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleUnderflow) {
auto spec = fromjson("{$convert: {input: '1E-1000', to: 'double'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
+ convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
ASSERT_STRING_CONTAINS(
exception.reason(),
@@ -2278,7 +2439,9 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleUnderflow) {
spec = fromjson("{$convert: {input: '-1E-1000', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
+ convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
ASSERT_STRING_CONTAINS(exception.reason(),
"Failed to parse number '-1E-1000' in $convert with no onError "
@@ -2293,20 +2456,24 @@ TEST_F(ExpressionConvertTest, ConvertStringToDoubleWithOnError) {
auto spec = fromjson("{$convert: {input: '" + kDoubleOverflow.toString() +
"', to: 'double', onError: '" + onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '" + kDoubleNegativeOverflow.toString() +
"', to: 'double', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '.5.', to: 'double', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '5.5f', to: 'double', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertStringToDecimal) {
@@ -2314,29 +2481,33 @@ TEST_F(ExpressionConvertTest, ConvertStringToDecimal) {
auto spec = fromjson("{$convert: {input: '5', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), 5, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), 5, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '2.02', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128("2.02"), BSONType::NumberDecimal);
+ convertExp->evaluate({}, &expCtx->variables), Decimal128("2.02"), BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '2.02E200', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128("2.02E200"), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}, &expCtx->variables),
+ Decimal128("2.02E200"),
+ BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '" + Decimal128::kLargestPositive.toString() +
"', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128::kLargestPositive, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}, &expCtx->variables),
+ Decimal128::kLargestPositive,
+ BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '" + Decimal128::kLargestNegative.toString() +
"', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128::kLargestNegative, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}, &expCtx->variables),
+ Decimal128::kLargestNegative,
+ BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertInfinityStringsToDecimal) {
@@ -2346,39 +2517,48 @@ TEST_F(ExpressionConvertTest, ConvertInfinityStringsToDecimal) {
auto spec = fromjson("{$convert: {input: 'Infinity', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: 'INF', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: 'infinity', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '+InFiNiTy', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), infValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), infValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-Infinity', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negInfValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negInfValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-INF', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negInfValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negInfValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-InFiNiTy', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negInfValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negInfValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-inf', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negInfValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negInfValue, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-infinity', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negInfValue, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negInfValue, BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertNanStringsToDecimal) {
@@ -2388,31 +2568,38 @@ TEST_F(ExpressionConvertTest, ConvertNanStringsToDecimal) {
auto spec = fromjson("{$convert: {input: 'nan', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), positiveNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), positiveNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: 'Nan', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), positiveNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), positiveNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: 'NaN', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), positiveNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), positiveNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '+NaN', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), positiveNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), positiveNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-NAN', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negativeNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negativeNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-nan', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negativeNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negativeNan, BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '-NaN', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), negativeNan, BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), negativeNan, BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertZeroStringsToDecimal) {
@@ -2420,28 +2607,28 @@ TEST_F(ExpressionConvertTest, ConvertZeroStringsToDecimal) {
auto spec = fromjson("{$convert: {input: '-0', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({});
+ auto result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDecimal);
ASSERT_TRUE(result.getDecimal().isZero());
ASSERT_TRUE(result.getDecimal().isNegative());
spec = fromjson("{$convert: {input: '-0.0', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDecimal);
ASSERT_TRUE(result.getDecimal().isZero());
ASSERT_TRUE(result.getDecimal().isNegative());
spec = fromjson("{$convert: {input: '+0', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDecimal);
ASSERT_TRUE(result.getDecimal().isZero());
ASSERT_FALSE(result.getDecimal().isNegative());
spec = fromjson("{$convert: {input: '+0.0', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- result = convertExp->evaluate({});
+ result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, 0, BSONType::NumberDecimal);
ASSERT_TRUE(result.getDecimal().isZero());
ASSERT_FALSE(result.getDecimal().isNegative());
@@ -2452,21 +2639,25 @@ TEST_F(ExpressionConvertTest, ConvertStringToDecimalOverflow) {
auto spec = fromjson("{$convert: {input: '1E6145', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(),
- "Conversion from string to decimal would overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(
+ exception.reason(),
+ "Conversion from string to decimal would overflow");
+ });
spec = fromjson("{$convert: {input: '-1E6145', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(),
- "Conversion from string to decimal would overflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(
+ exception.reason(),
+ "Conversion from string to decimal would overflow");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToDecimalUnderflow) {
@@ -2474,21 +2665,25 @@ TEST_F(ExpressionConvertTest, ConvertStringToDecimalUnderflow) {
auto spec = fromjson("{$convert: {input: '1E-6178', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(),
- "Conversion from string to decimal would underflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(
+ exception.reason(),
+ "Conversion from string to decimal would underflow");
+ });
spec = fromjson("{$convert: {input: '-1E-6177', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(),
- "Conversion from string to decimal would underflow");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(
+ exception.reason(),
+ "Conversion from string to decimal would underflow");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToDecimalWithPrecisionLoss) {
@@ -2498,12 +2693,12 @@ TEST_F(ExpressionConvertTest, ConvertStringToDecimalWithPrecisionLoss) {
fromjson("{$convert: {input: '10000000000000000000000000000000001', to: 'decimal'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128("1e34"), BSONType::NumberDecimal);
+ convertExp->evaluate({}, &expCtx->variables), Decimal128("1e34"), BSONType::NumberDecimal);
spec = fromjson("{$convert: {input: '1.1250000000000000000000000000000001', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), Decimal128("1.125"), BSONType::NumberDecimal);
+ convertExp->evaluate({}, &expCtx->variables), Decimal128("1.125"), BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertTest, ConvertStringToDecimalWithOnError) {
@@ -2513,12 +2708,14 @@ TEST_F(ExpressionConvertTest, ConvertStringToDecimalWithOnError) {
auto spec =
fromjson("{$convert: {input: '1E6145', to: 'decimal', onError: '" + onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec =
fromjson("{$convert: {input: '-1E-6177', to: 'decimal', onError: '" + onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertStringToNumberFailsForHexStrings) {
@@ -2530,43 +2727,53 @@ TEST_F(ExpressionConvertTest, ConvertStringToNumberFailsForHexStrings) {
auto spec = fromjson("{$convert: {input: '0xFF', to: 'int'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: '0xFF', to: 'long'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: '0xFF', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: '0xFF', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: '0x00', to: 'int'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: '0x00', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}), AssertionException, invalidHexFailure);
+ ASSERT_THROWS_WITH_CHECK(
+ convertExp->evaluate({}, &expCtx->variables), AssertionException, invalidHexFailure);
spec = fromjson("{$convert: {input: 'FF', to: 'double'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Did not consume whole number");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Did not consume whole number");
+ });
spec = fromjson("{$convert: {input: 'FF', to: 'decimal'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Failed to parse string to decimal");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Failed to parse string to decimal");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToOID) {
@@ -2575,12 +2782,14 @@ TEST_F(ExpressionConvertTest, ConvertStringToOID) {
auto spec = fromjson("{$convert: {input: '" + oid.toString() + "', to: 'objectId'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), oid, BSONType::jstOID);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), oid, BSONType::jstOID);
spec = fromjson("{$convert: {input: '123456789abcdef123456789', to: 'objectId'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate({}), OID("123456789abcdef123456789"), BSONType::jstOID);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}, &expCtx->variables),
+ OID("123456789abcdef123456789"),
+ BSONType::jstOID);
}
TEST_F(ExpressionConvertTest, ConvertStringToOIDFailsForInvalidHexStrings) {
@@ -2588,27 +2797,33 @@ TEST_F(ExpressionConvertTest, ConvertStringToOIDFailsForInvalidHexStrings) {
auto spec = fromjson("{$convert: {input: 'InvalidHexButSizeCorrect', to: 'objectId'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Invalid character found in hex string");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Invalid character found in hex string");
+ });
spec = fromjson("{$convert: {input: 'InvalidSize', to: 'objectId'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Invalid string length for parsing to OID");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Invalid string length for parsing to OID");
+ });
spec = fromjson("{$convert: {input: '0x123456789abcdef123456789', to: 'objectId'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_WITH_CHECK(
- convertExp->evaluate({}), AssertionException, [](const AssertionException& exception) {
- ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
- ASSERT_STRING_CONTAINS(exception.reason(), "Invalid string length for parsing to OID");
- });
+ ASSERT_THROWS_WITH_CHECK(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ [](const AssertionException& exception) {
+ ASSERT_EQ(exception.code(), ErrorCodes::ConversionFailure);
+ ASSERT_STRING_CONTAINS(exception.reason(),
+ "Invalid string length for parsing to OID");
+ });
}
TEST_F(ExpressionConvertTest, ConvertStringToOIDWithOnError) {
@@ -2619,17 +2834,20 @@ TEST_F(ExpressionConvertTest, ConvertStringToOIDWithOnError) {
fromjson("{$convert: {input: 'InvalidHexButSizeCorrect', to: 'objectId', onError: '" +
onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: 'InvalidSize', to: 'objectId', onError: '" + onErrorValue +
"'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
spec = fromjson("{$convert: {input: '0x123456789abcdef123456789', to: 'objectId', onError: '" +
onErrorValue + "'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate({}), onErrorValue, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate({}, &expCtx->variables), onErrorValue, BSONType::String);
}
TEST_F(ExpressionConvertTest, ConvertStringToDateRejectsUnparsableString) {
@@ -2637,11 +2855,15 @@ TEST_F(ExpressionConvertTest, ConvertStringToDateRejectsUnparsableString) {
auto spec = fromjson("{$convert: {input: '60.Monday1770/06:59', to: 'date'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(convertExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
spec = fromjson("{$convert: {input: 'Definitely not a date', to: 'date'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(convertExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionConvertTest, ConvertStringToDateRejectsTimezoneNameInString) {
@@ -2649,11 +2871,15 @@ TEST_F(ExpressionConvertTest, ConvertStringToDateRejectsTimezoneNameInString) {
auto spec = fromjson("{$convert: {input: '2017-07-13T10:02:57 Europe/London', to: 'date'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(convertExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
spec = fromjson("{$convert: {input: 'July 4, 2017 Europe/London', to: 'date'}}");
convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(convertExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convertExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionConvertTest, ConvertStringToDate) {
@@ -2662,15 +2888,17 @@ TEST_F(ExpressionConvertTest, ConvertStringToDate) {
auto spec = fromjson("{$convert: {input: '$path1', to: 'date'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({{"path1", Value("2017-07-06T12:35:37Z"_sd)}});
+ auto result =
+ convertExp->evaluate({{"path1", Value("2017-07-06T12:35:37Z"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-06T12:35:37.000Z", result.toString());
- result = convertExp->evaluate({{"path1", Value("2017-07-06T12:35:37.513Z"_sd)}});
+ result =
+ convertExp->evaluate({{"path1", Value("2017-07-06T12:35:37.513Z"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-06T12:35:37.513Z", result.toString());
- result = convertExp->evaluate({{"path1", Value("2017-07-06"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("2017-07-06"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-06T00:00:00.000Z", result.toString());
}
@@ -2681,11 +2909,13 @@ TEST_F(ExpressionConvertTest, ConvertStringWithTimezoneToDate) {
auto spec = fromjson("{$convert: {input: '$path1', to: 'date'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({{"path1", Value("2017-07-14T12:02:44.771 GMT+02:00"_sd)}});
+ auto result = convertExp->evaluate({{"path1", Value("2017-07-14T12:02:44.771 GMT+02:00"_sd)}},
+ &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-14T10:02:44.771Z", result.toString());
- result = convertExp->evaluate({{"path1", Value("2017-07-14T12:02:44.771 A"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("2017-07-14T12:02:44.771 A"_sd)}},
+ &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-14T11:02:44.771Z", result.toString());
}
@@ -2696,15 +2926,15 @@ TEST_F(ExpressionConvertTest, ConvertVerbalStringToDate) {
auto spec = fromjson("{$convert: {input: '$path1', to: 'date'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({{"path1", Value("July 4th, 2017"_sd)}});
+ auto result = convertExp->evaluate({{"path1", Value("July 4th, 2017"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-04T00:00:00.000Z", result.toString());
- result = convertExp->evaluate({{"path1", Value("July 4th, 2017 12pm"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("July 4th, 2017 12pm"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-04T12:00:00.000Z", result.toString());
- result = convertExp->evaluate({{"path1", Value("2017-Jul-04 noon"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("2017-Jul-04 noon"_sd)}}, &expCtx->variables);
ASSERT_EQ(result.getType(), BSONType::Date);
ASSERT_EQ("2017-07-04T12:00:00.000Z", result.toString());
}
@@ -2717,13 +2947,14 @@ TEST_F(ExpressionConvertTest, ConvertStringToDateWithOnError) {
fromjson("{$convert: {input: '$path1', to: 'date', onError: '" + onErrorValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({{"path1", Value("Not a date"_sd)}});
+ auto result = convertExp->evaluate({{"path1", Value("Not a date"_sd)}}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, onErrorValue, BSONType::String);
- result = convertExp->evaluate({{"path1", Value("60.Monday1770/06:59"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("60.Monday1770/06:59"_sd)}}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, onErrorValue, BSONType::String);
- result = convertExp->evaluate({{"path1", Value("2017-07-13T10:02:57 Europe/London"_sd)}});
+ result = convertExp->evaluate({{"path1", Value("2017-07-13T10:02:57 Europe/London"_sd)}},
+ &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, onErrorValue, BSONType::String);
}
@@ -2735,10 +2966,10 @@ TEST_F(ExpressionConvertTest, ConvertStringToDateWithOnNull) {
fromjson("{$convert: {input: '$path1', to: 'date', onNull: '" + onNullValue + "'}}");
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- auto result = convertExp->evaluate({});
+ auto result = convertExp->evaluate({}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, onNullValue, BSONType::String);
- result = convertExp->evaluate({{"path1", Value(BSONNULL)}});
+ result = convertExp->evaluate({{"path1", Value(BSONNULL)}}, &expCtx->variables);
ASSERT_VALUE_CONTENTS_AND_TYPE(result, onNullValue, BSONType::String);
}
@@ -2752,54 +2983,67 @@ TEST_F(ExpressionConvertTest, FormatDouble) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document zeroInput{{"path1", 0.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(zeroInput), "0"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(zeroInput, &expCtx->variables), "0"_sd, BSONType::String);
Document negativeZeroInput{{"path1", -0.0}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeZeroInput), "-0"_sd, BSONType::String);
+ convertExp->evaluate(negativeZeroInput, &expCtx->variables), "-0"_sd, BSONType::String);
Document positiveIntegerInput{{"path1", 1337.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveIntegerInput), "1337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveIntegerInput, &expCtx->variables),
+ "1337"_sd,
+ BSONType::String);
Document negativeIntegerInput{{"path1", -1337.0}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeIntegerInput), "-1337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeIntegerInput, &expCtx->variables),
+ "-1337"_sd,
+ BSONType::String);
Document positiveFractionalInput{{"path1", 0.1337}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveFractionalInput), "0.1337"_sd, BSONType::String);
+ convertExp->evaluate(positiveFractionalInput, &expCtx->variables),
+ "0.1337"_sd,
+ BSONType::String);
Document negativeFractionalInput{{"path1", -0.1337}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeFractionalInput), "-0.1337"_sd, BSONType::String);
+ convertExp->evaluate(negativeFractionalInput, &expCtx->variables),
+ "-0.1337"_sd,
+ BSONType::String);
Document positiveLargeInput{{"path1", 1.3e37}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveLargeInput), "1.3e+37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveLargeInput, &expCtx->variables),
+ "1.3e+37"_sd,
+ BSONType::String);
Document negativeLargeInput{{"path1", -1.3e37}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeLargeInput), "-1.3e+37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeLargeInput, &expCtx->variables),
+ "-1.3e+37"_sd,
+ BSONType::String);
Document positiveTinyInput{{"path1", 1.3e-37}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveTinyInput), "1.3e-37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveTinyInput, &expCtx->variables),
+ "1.3e-37"_sd,
+ BSONType::String);
Document negativeTinyInput{{"path1", -1.3e-37}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeTinyInput), "-1.3e-37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeTinyInput, &expCtx->variables),
+ "-1.3e-37"_sd,
+ BSONType::String);
Document infinityInput{{"path1", std::numeric_limits<double>::infinity()}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(infinityInput), "Infinity"_sd, BSONType::String);
+ convertExp->evaluate(infinityInput, &expCtx->variables), "Infinity"_sd, BSONType::String);
Document negativeInfinityInput{{"path1", -std::numeric_limits<double>::infinity()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeInfinityInput), "-Infinity"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeInfinityInput, &expCtx->variables),
+ "-Infinity"_sd,
+ BSONType::String);
Document nanInput{{"path1", std::numeric_limits<double>::quiet_NaN()}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "NaN"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "NaN"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatObjectId) {
@@ -2812,12 +3056,14 @@ TEST_F(ExpressionConvertTest, FormatObjectId) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document zeroInput{{"path1", OID("000000000000000000000000")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(zeroInput), "000000000000000000000000"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(zeroInput, &expCtx->variables),
+ "000000000000000000000000"_sd,
+ BSONType::String);
Document simpleInput{{"path1", OID("0123456789abcdef01234567")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(simpleInput), "0123456789abcdef01234567"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(simpleInput, &expCtx->variables),
+ "0123456789abcdef01234567"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatBool) {
@@ -2830,10 +3076,12 @@ TEST_F(ExpressionConvertTest, FormatBool) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document trueInput{{"path1", true}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(trueInput), "true"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(trueInput, &expCtx->variables), "true"_sd, BSONType::String);
Document falseInput{{"path1", false}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(falseInput), "false"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(falseInput, &expCtx->variables), "false"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatDate) {
@@ -2846,12 +3094,14 @@ TEST_F(ExpressionConvertTest, FormatDate) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document epochInput{{"path1", Date_t::fromMillisSinceEpoch(0LL)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(epochInput), "1970-01-01T00:00:00.000Z"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(epochInput, &expCtx->variables),
+ "1970-01-01T00:00:00.000Z"_sd,
+ BSONType::String);
Document dateInput{{"path1", Date_t::fromMillisSinceEpoch(872835240000)}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(dateInput), "1997-08-29T06:14:00.000Z"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(dateInput, &expCtx->variables),
+ "1997-08-29T06:14:00.000Z"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatInt) {
@@ -2864,15 +3114,16 @@ TEST_F(ExpressionConvertTest, FormatInt) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document zeroInput{{"path1", int{0}}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(zeroInput), "0"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(zeroInput, &expCtx->variables), "0"_sd, BSONType::String);
Document positiveInput{{"path1", int{1337}}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveInput), "1337"_sd, BSONType::String);
+ convertExp->evaluate(positiveInput, &expCtx->variables), "1337"_sd, BSONType::String);
Document negativeInput{{"path1", int{-1337}}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeInput), "-1337"_sd, BSONType::String);
+ convertExp->evaluate(negativeInput, &expCtx->variables), "-1337"_sd, BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatLong) {
@@ -2885,15 +3136,18 @@ TEST_F(ExpressionConvertTest, FormatLong) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document zeroInput{{"path1", 0LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(zeroInput), "0"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(zeroInput, &expCtx->variables), "0"_sd, BSONType::String);
Document positiveInput{{"path1", 1337133713371337LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveInput), "1337133713371337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveInput, &expCtx->variables),
+ "1337133713371337"_sd,
+ BSONType::String);
Document negativeInput{{"path1", -1337133713371337LL}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeInput), "-1337133713371337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeInput, &expCtx->variables),
+ "-1337133713371337"_sd,
+ BSONType::String);
}
TEST_F(ExpressionConvertTest, FormatDecimal) {
@@ -2906,83 +3160,103 @@ TEST_F(ExpressionConvertTest, FormatDecimal) {
auto convertExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
Document zeroInput{{"path1", Decimal128("0")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(zeroInput), "0"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(zeroInput, &expCtx->variables), "0"_sd, BSONType::String);
Document negativeZeroInput{{"path1", Decimal128("-0")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeZeroInput), "-0"_sd, BSONType::String);
+ convertExp->evaluate(negativeZeroInput, &expCtx->variables), "-0"_sd, BSONType::String);
Document preciseZeroInput{{"path1", Decimal128("0.0")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(preciseZeroInput), "0.0"_sd, BSONType::String);
+ convertExp->evaluate(preciseZeroInput, &expCtx->variables), "0.0"_sd, BSONType::String);
Document negativePreciseZeroInput{{"path1", Decimal128("-0.0")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativePreciseZeroInput), "-0.0"_sd, BSONType::String);
+ convertExp->evaluate(negativePreciseZeroInput, &expCtx->variables),
+ "-0.0"_sd,
+ BSONType::String);
Document extraPreciseZeroInput{{"path1", Decimal128("0.0000")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(extraPreciseZeroInput), "0.0000"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(extraPreciseZeroInput, &expCtx->variables),
+ "0.0000"_sd,
+ BSONType::String);
Document positiveIntegerInput{{"path1", Decimal128("1337")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveIntegerInput), "1337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveIntegerInput, &expCtx->variables),
+ "1337"_sd,
+ BSONType::String);
Document largeIntegerInput{{"path1", Decimal128("13370000000000000000000000000000000")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(largeIntegerInput),
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(largeIntegerInput, &expCtx->variables),
"1.337000000000000000000000000000000E+34"_sd,
BSONType::String);
Document negativeIntegerInput{{"path1", Decimal128("-1337")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeIntegerInput), "-1337"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeIntegerInput, &expCtx->variables),
+ "-1337"_sd,
+ BSONType::String);
Document positiveFractionalInput{{"path1", Decimal128("0.1337")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveFractionalInput), "0.1337"_sd, BSONType::String);
+ convertExp->evaluate(positiveFractionalInput, &expCtx->variables),
+ "0.1337"_sd,
+ BSONType::String);
Document positivePreciseFractionalInput{{"path1", Decimal128("0.133700")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positivePreciseFractionalInput), "0.133700"_sd, BSONType::String);
+ convertExp->evaluate(positivePreciseFractionalInput, &expCtx->variables),
+ "0.133700"_sd,
+ BSONType::String);
Document negativeFractionalInput{{"path1", Decimal128("-0.1337")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeFractionalInput), "-0.1337"_sd, BSONType::String);
+ convertExp->evaluate(negativeFractionalInput, &expCtx->variables),
+ "-0.1337"_sd,
+ BSONType::String);
Document negativePreciseFractionalInput{{"path1", Decimal128("-0.133700")}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativePreciseFractionalInput), "-0.133700"_sd, BSONType::String);
+ convertExp->evaluate(negativePreciseFractionalInput, &expCtx->variables),
+ "-0.133700"_sd,
+ BSONType::String);
Document positiveLargeInput{{"path1", Decimal128("1.3e37")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveLargeInput), "1.3E+37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveLargeInput, &expCtx->variables),
+ "1.3E+37"_sd,
+ BSONType::String);
Document negativeLargeInput{{"path1", Decimal128("-1.3e37")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeLargeInput), "-1.3E+37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeLargeInput, &expCtx->variables),
+ "-1.3E+37"_sd,
+ BSONType::String);
Document positiveTinyInput{{"path1", Decimal128("1.3e-37")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(positiveTinyInput), "1.3E-37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(positiveTinyInput, &expCtx->variables),
+ "1.3E-37"_sd,
+ BSONType::String);
Document negativeTinyInput{{"path1", Decimal128("-1.3e-37")}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeTinyInput), "-1.3E-37"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeTinyInput, &expCtx->variables),
+ "-1.3E-37"_sd,
+ BSONType::String);
Document infinityInput{{"path1", Decimal128::kPositiveInfinity}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(infinityInput), "Infinity"_sd, BSONType::String);
+ convertExp->evaluate(infinityInput, &expCtx->variables), "Infinity"_sd, BSONType::String);
Document negativeInfinityInput{{"path1", Decimal128::kNegativeInfinity}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeInfinityInput), "-Infinity"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(negativeInfinityInput, &expCtx->variables),
+ "-Infinity"_sd,
+ BSONType::String);
Document nanInput{{"path1", Decimal128::kPositiveNaN}};
- ASSERT_VALUE_CONTENTS_AND_TYPE(convertExp->evaluate(nanInput), "NaN"_sd, BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convertExp->evaluate(nanInput, &expCtx->variables), "NaN"_sd, BSONType::String);
Document negativeNaNInput{{"path1", Decimal128::kNegativeNaN}};
ASSERT_VALUE_CONTENTS_AND_TYPE(
- convertExp->evaluate(negativeNaNInput), "NaN"_sd, BSONType::String);
+ convertExp->evaluate(negativeNaNInput, &expCtx->variables), "NaN"_sd, BSONType::String);
}
} // namespace ExpressionConvertTest
@@ -3039,7 +3313,9 @@ TEST_F(ExpressionConvertShortcutsTest, AcceptsSingleArgumentInArrayOrByItself) {
spec = BSON("$toInt" << BSON_ARRAY(BSON_ARRAY("1")));
convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(convert->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convert->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToInts) {
@@ -3049,7 +3325,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToInts) {
<< "1");
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(1), BSONType::NumberInt);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(1), BSONType::NumberInt);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToLongs) {
@@ -3059,7 +3336,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToLongs) {
<< "1");
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(1), BSONType::NumberLong);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(1), BSONType::NumberLong);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToDoubles) {
@@ -3069,7 +3347,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToDoubles) {
<< "1");
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(1), BSONType::NumberDouble);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(1), BSONType::NumberDouble);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToDecimals) {
@@ -3079,7 +3358,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToDecimals) {
<< "1");
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(1), BSONType::NumberDecimal);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(1), BSONType::NumberDecimal);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToDates) {
@@ -3088,8 +3368,9 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToDates) {
BSONObj spec = BSON("$toDate" << 0LL);
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convert->evaluate({}), Value(Date_t::fromMillisSinceEpoch(0)), BSONType::Date);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}, &expCtx->variables),
+ Value(Date_t::fromMillisSinceEpoch(0)),
+ BSONType::Date);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToObjectIds) {
@@ -3099,8 +3380,9 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToObjectIds) {
BSONObj spec = BSON("$toObjectId" << hexString);
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(
- convert->evaluate({}), Value(OID::createFromString(hexString)), BSONType::jstOID);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}, &expCtx->variables),
+ Value(OID::createFromString(hexString)),
+ BSONType::jstOID);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToString) {
@@ -3109,7 +3391,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToString) {
BSONObj spec = BSON("$toString" << 1);
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value("1"_sd), BSONType::String);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value("1"_sd), BSONType::String);
}
TEST_F(ExpressionConvertShortcutsTest, ConvertsToBool) {
@@ -3118,7 +3401,8 @@ TEST_F(ExpressionConvertShortcutsTest, ConvertsToBool) {
BSONObj spec = BSON("$toBool" << 1);
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(true), BSONType::Bool);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(true), BSONType::Bool);
}
TEST_F(ExpressionConvertShortcutsTest, ReturnsNullOnNullishInput) {
@@ -3127,13 +3411,15 @@ TEST_F(ExpressionConvertShortcutsTest, ReturnsNullOnNullishInput) {
BSONObj spec = BSON("$toBool" << BSONNULL);
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(BSONNULL), BSONType::jstNULL);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(BSONNULL), BSONType::jstNULL);
spec = BSON("$toInt"
<< "$missing");
convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_VALUE_CONTENTS_AND_TYPE(convert->evaluate({}), Value(BSONNULL), BSONType::jstNULL);
+ ASSERT_VALUE_CONTENTS_AND_TYPE(
+ convert->evaluate({}, &expCtx->variables), Value(BSONNULL), BSONType::jstNULL);
}
TEST_F(ExpressionConvertShortcutsTest, ThrowsOnConversionFailure) {
@@ -3143,13 +3429,17 @@ TEST_F(ExpressionConvertShortcutsTest, ThrowsOnConversionFailure) {
<< "not an int");
auto convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_THROWS_CODE(convert->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convert->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
spec = BSON("$toObjectId"
<< "not all hex values");
convert = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_TRUE(dynamic_cast<ExpressionConvert*>(convert.get()));
- ASSERT_THROWS_CODE(convert->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(convert->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
} // namespace ExpressionConvertShortcutsTest
diff --git a/src/mongo/db/pipeline/expression_date_test.cpp b/src/mongo/db/pipeline/expression_date_test.cpp
index 528c0da9541..67e798d17af 100644
--- a/src/mongo/db/pipeline/expression_date_test.cpp
+++ b/src/mongo/db/pipeline/expression_date_test.cpp
@@ -143,27 +143,27 @@ TEST_F(ExpressionDateFromPartsTest, TestThatOutOfRangeValuesRollOver) {
auto spec = BSON("$dateFromParts" << BSON("year" << 2017 << "month" << -1));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto dateVal = Date_t::fromMillisSinceEpoch(1477958400000); // 11/1/2016 in ms.
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromParts" << BSON("year" << 2017 << "day" << -1));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
dateVal = Date_t::fromMillisSinceEpoch(1483056000000); // 12/30/2016
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromParts" << BSON("year" << 2017 << "hour" << 25));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
dateVal = Date_t::fromMillisSinceEpoch(1483318800000); // 1/2/2017 01:00:00
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromParts" << BSON("year" << 2017 << "minute" << 61));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
dateVal = Date_t::fromMillisSinceEpoch(1483232460000); // 1/1/2017 01:01:00
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromParts" << BSON("year" << 2017 << "second" << 61));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
dateVal = Date_t::fromMillisSinceEpoch(1483228861000); // 1/1/2017 00:01:01
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
}
} // namespace ExpressionDateFromPartsTest
@@ -354,14 +354,16 @@ TEST_F(DateExpressionTest, RejectsArraysWithinObjectSpecification) {
// It will parse as an ExpressionArray, and fail at runtime.
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"_id", 0}};
- ASSERT_THROWS_CODE(dateExp->evaluate(contextDoc), AssertionException, 16006);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(contextDoc, &expCtx->variables), AssertionException, 16006);
// Test that it rejects an array for the timezone option.
spec =
BSON(expName << BSON("date" << Date_t{} << "timezone" << BSON_ARRAY("Europe/London")));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
contextDoc = Document{{"_id", 0}};
- ASSERT_THROWS_CODE(dateExp->evaluate(contextDoc), AssertionException, 40533);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(contextDoc, &expCtx->variables), AssertionException, 40533);
}
}
@@ -371,7 +373,8 @@ TEST_F(DateExpressionTest, RejectsTypesThatCannotCoerceToDate) {
BSONObj spec = BSON(expName << "$stringField");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"stringField", "string"_sd}};
- ASSERT_THROWS_CODE(dateExp->evaluate(contextDoc), AssertionException, 16006);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(contextDoc, &expCtx->variables), AssertionException, 16006);
}
}
@@ -381,7 +384,7 @@ TEST_F(DateExpressionTest, AcceptsObjectIds) {
BSONObj spec = BSON(expName << "$oid");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"oid", OID::gen()}};
- dateExp->evaluate(contextDoc); // Should not throw.
+ dateExp->evaluate(contextDoc, &expCtx->variables); // Should not throw.
}
}
@@ -391,7 +394,7 @@ TEST_F(DateExpressionTest, AcceptsTimestamps) {
BSONObj spec = BSON(expName << "$ts");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"ts", Timestamp{Date_t{}}}};
- dateExp->evaluate(contextDoc); // Should not throw.
+ dateExp->evaluate(contextDoc, &expCtx->variables); // Should not throw.
}
}
@@ -402,7 +405,8 @@ TEST_F(DateExpressionTest, RejectsNonStringTimezone) {
<< "$intField"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"intField", 4}};
- ASSERT_THROWS_CODE(dateExp->evaluate(contextDoc), AssertionException, 40533);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(contextDoc, &expCtx->variables), AssertionException, 40533);
}
}
@@ -413,7 +417,8 @@ TEST_F(DateExpressionTest, RejectsUnrecognizedTimeZoneSpecification) {
<< "UNRECOGNIZED!"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"_id", 0}};
- ASSERT_THROWS_CODE(dateExp->evaluate(contextDoc), AssertionException, 40485);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(contextDoc, &expCtx->variables), AssertionException, 40485);
}
}
@@ -498,7 +503,7 @@ TEST_F(DateExpressionTest, DoesRespectTimeZone) {
<< "America/New_York"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
auto contextDoc = Document{{"_id", 0}};
- dateExp->evaluate(contextDoc); // Should not throw.
+ dateExp->evaluate(contextDoc, &expCtx->variables); // Should not throw.
}
// Make sure the time zone is used during evaluation.
@@ -506,14 +511,14 @@ TEST_F(DateExpressionTest, DoesRespectTimeZone) {
auto specWithoutTimezone = BSON("$hour" << BSON("date" << date));
auto hourWithoutTimezone =
Expression::parseExpression(expCtx, specWithoutTimezone, expCtx->variablesParseState)
- ->evaluate({});
+ ->evaluate({}, &expCtx->variables);
ASSERT_VALUE_EQ(hourWithoutTimezone, Value(19));
auto specWithTimezone = BSON("$hour" << BSON("date" << date << "timezone"
<< "America/New_York"));
auto hourWithTimezone =
Expression::parseExpression(expCtx, specWithTimezone, expCtx->variablesParseState)
- ->evaluate({});
+ ->evaluate({}, &expCtx->variables);
ASSERT_VALUE_EQ(hourWithTimezone, Value(15));
}
@@ -528,30 +533,30 @@ TEST_F(DateExpressionTest, DoesResultInNullIfGivenNullishInput) {
auto spec = BSON(expName << BSON("date"
<< "$missing"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
spec = BSON(expName << BSON("date" << BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
spec = BSON(expName << BSON("date" << BSONUndefined));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
// Test that the expression results in null if the date is present but the timezone is
// nullish.
spec = BSON(expName << BSON("date" << Date_t{} << "timezone"
<< "$missing"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
spec = BSON(expName << BSON("date" << Date_t{} << "timezone" << BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
spec = BSON(expName << BSON("date" << Date_t{} << "timezone" << BSONUndefined));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
// Test that the expression results in null if the date and timezone both nullish.
spec = BSON(expName << BSON("date"
@@ -559,7 +564,7 @@ TEST_F(DateExpressionTest, DoesResultInNullIfGivenNullishInput) {
<< "timezone"
<< BSONUndefined));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
// Test that the expression results in null if the date is nullish and timezone is present.
spec = BSON(expName << BSON("date"
@@ -567,7 +572,7 @@ TEST_F(DateExpressionTest, DoesResultInNullIfGivenNullishInput) {
<< "timezone"
<< "Europe/London"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(contextDoc, &expCtx->variables));
}
}
@@ -707,7 +712,7 @@ TEST_F(ExpressionDateToStringTest, ReturnsOnNullValueWhenInputIsNullish) {
<< "onNull"
<< "null default"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("null default"_sd), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateToString" << BSON("format"
<< "%Y-%m-%d"
@@ -716,7 +721,7 @@ TEST_F(ExpressionDateToStringTest, ReturnsOnNullValueWhenInputIsNullish) {
<< "onNull"
<< BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateToString" << BSON("format"
<< "%Y-%m-%d"
@@ -725,7 +730,7 @@ TEST_F(ExpressionDateToStringTest, ReturnsOnNullValueWhenInputIsNullish) {
<< "onNull"
<< "null default"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("null default"_sd), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateToString" << BSON("format"
<< "%Y-%m-%d"
@@ -734,7 +739,7 @@ TEST_F(ExpressionDateToStringTest, ReturnsOnNullValueWhenInputIsNullish) {
<< "onNull"
<< "$alsoMissing"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateToStringTest, ReturnsNullIfInputDateIsNullish) {
@@ -742,8 +747,9 @@ TEST_F(ExpressionDateToStringTest, ReturnsNullIfInputDateIsNullish) {
auto spec = fromjson("{$dateToString: {date: '$date'}}");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{{"date", BSONNULL}}));
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL),
+ dateExp->evaluate(Document{{"date", BSONNULL}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateToStringTest, ReturnsNullIfFormatIsNullish) {
@@ -751,9 +757,11 @@ TEST_F(ExpressionDateToStringTest, ReturnsNullIfFormatIsNullish) {
auto spec = fromjson("{$dateToString: {date: '$date', format: '$format'}}");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
+ ASSERT_VALUE_EQ(
+ Value(BSONNULL),
+ dateExp->evaluate(Document{{"date", Date_t{}}, {"format", BSONNULL}}, &expCtx->variables));
ASSERT_VALUE_EQ(Value(BSONNULL),
- dateExp->evaluate(Document{{"date", Date_t{}}, {"format", BSONNULL}}));
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{{"date", Date_t{}}}));
+ dateExp->evaluate(Document{{"date", Date_t{}}}, &expCtx->variables));
}
TEST_F(ExpressionDateToStringTest, UsesDefaultFormatIfNoneSpecified) {
@@ -762,7 +770,7 @@ TEST_F(ExpressionDateToStringTest, UsesDefaultFormatIfNoneSpecified) {
auto spec = fromjson("{$dateToString: {date: '$date'}}");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_VALUE_EQ(Value("1970-01-01T00:00:00.000Z"_sd),
- dateExp->evaluate(Document{{"date", Date_t{}}}));
+ dateExp->evaluate(Document{{"date", Date_t{}}}, &expCtx->variables));
}
TEST_F(ExpressionDateToStringTest, FailsForInvalidTimezoneRegardlessOfInputDate) {
@@ -770,11 +778,14 @@ TEST_F(ExpressionDateToStringTest, FailsForInvalidTimezoneRegardlessOfInputDate)
auto spec = fromjson("{$dateToString: {date: '$date', timezone: '$tz'}}");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{{"date", BSONNULL}, {"tz", "invalid"_sd}}),
- AssertionException,
- 40485);
ASSERT_THROWS_CODE(
- dateExp->evaluate(Document{{"date", BSONNULL}, {"tz", 5}}), AssertionException, 40517);
+ dateExp->evaluate(Document{{"date", BSONNULL}, {"tz", "invalid"_sd}}, &expCtx->variables),
+ AssertionException,
+ 40485);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(Document{{"date", BSONNULL}, {"tz", 5}}, &expCtx->variables),
+ AssertionException,
+ 40517);
}
TEST_F(ExpressionDateToStringTest, FailsForInvalidFormatStrings) {
@@ -783,12 +794,12 @@ TEST_F(ExpressionDateToStringTest, FailsForInvalidFormatStrings) {
auto spec = BSON("$dateToString" << BSON("date" << Date_t{} << "format"
<< "%n"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 18536);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 18536);
spec = BSON("$dateToString" << BSON("date" << Date_t{} << "format"
<< "%Y%"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 18535);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 18535);
}
TEST_F(ExpressionDateToStringTest, FailsForInvalidFormatRegardlessOfInputDate) {
@@ -797,16 +808,21 @@ TEST_F(ExpressionDateToStringTest, FailsForInvalidFormatRegardlessOfInputDate) {
auto spec = fromjson("{$dateToString: {date: '$date', format: '$format', onNull: 0}}");
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
ASSERT_THROWS_CODE(
- dateExp->evaluate(Document{{"date", BSONNULL}, {"format", 5}}), AssertionException, 18533);
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{{"date", BSONNULL}, {"format", "%n"_sd}}),
- AssertionException,
- 18536);
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{{"date", BSONNULL}, {"format", "%"_sd}}),
- AssertionException,
- 18535);
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{{"date", "Invalid date"_sd}, {"format", 5}}),
- AssertionException,
- 18533);
+ dateExp->evaluate(Document{{"date", BSONNULL}, {"format", 5}}, &expCtx->variables),
+ AssertionException,
+ 18533);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(Document{{"date", BSONNULL}, {"format", "%n"_sd}}, &expCtx->variables),
+ AssertionException,
+ 18536);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(Document{{"date", BSONNULL}, {"format", "%"_sd}}, &expCtx->variables),
+ AssertionException,
+ 18535);
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(Document{{"date", "Invalid date"_sd}, {"format", 5}}, &expCtx->variables),
+ AssertionException,
+ 18533);
}
} // namespace ExpressionDateToStringTest
@@ -894,7 +910,7 @@ TEST_F(ExpressionDateFromStringTest, OptimizesToConstantIfAllInputsAreConstant)
ASSERT(dynamic_cast<ExpressionConstant*>(dateExp->optimize().get()));
Date_t dateVal = Date_t::fromMillisSinceEpoch(1499173797000);
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-04T13:09:57"
@@ -914,7 +930,7 @@ TEST_F(ExpressionDateFromStringTest, OptimizesToConstantIfAllInputsAreConstant)
ASSERT(dynamic_cast<ExpressionConstant*>(dateExp->optimize().get()));
dateVal = Date_t::fromMillisSinceEpoch(1499170197000);
- ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(dateVal), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-04T13:09:57"
@@ -986,7 +1002,9 @@ TEST_F(ExpressionDateFromStringTest, RejectsUnparsableString) {
auto spec = BSON("$dateFromString" << BSON("dateString"
<< "60.Monday1770/06:59"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInString) {
@@ -995,12 +1013,16 @@ TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInString) {
auto spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-13T10:02:57 Europe/London"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
spec = BSON("$dateFromString" << BSON("dateString"
<< "July 4, 2017 Europe/London"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInStringAndArgument) {
@@ -1012,7 +1034,9 @@ TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInStringAndArgument) {
<< "timezone"
<< "Europe/London"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
// Test with timezone abbreviation and timezone
spec = BSON("$dateFromString" << BSON("dateString"
@@ -1020,7 +1044,9 @@ TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInStringAndArgument) {
<< "timezone"
<< "Europe/London"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
// Test with GMT offset and timezone
spec = BSON("$dateFromString" << BSON("dateString"
@@ -1028,7 +1054,9 @@ TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInStringAndArgument) {
<< "timezone"
<< "Europe/London"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
// Test with GMT offset and GMT timezone
spec = BSON("$dateFromString" << BSON("dateString"
@@ -1036,7 +1064,9 @@ TEST_F(ExpressionDateFromStringTest, RejectsTimeZoneInStringAndArgument) {
<< "timezone"
<< "GMT"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionDateFromStringTest, RejectsNonStringFormat) {
@@ -1047,14 +1077,14 @@ TEST_F(ExpressionDateFromStringTest, RejectsNonStringFormat) {
<< "format"
<< 2));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40684);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40684);
spec = BSON("$dateFromString" << BSON("dateString"
<< "July 4, 2017"
<< "format"
<< true));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40684);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40684);
}
TEST_F(ExpressionDateFromStringTest, RejectsStringsThatDoNotMatchFormat) {
@@ -1065,14 +1095,18 @@ TEST_F(ExpressionDateFromStringTest, RejectsStringsThatDoNotMatchFormat) {
<< "format"
<< "%Y-%m-%d"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07"
<< "format"
<< "%m-%Y"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, ErrorCodes::ConversionFailure);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables),
+ AssertionException,
+ ErrorCodes::ConversionFailure);
}
TEST_F(ExpressionDateFromStringTest, EscapeCharacterAllowsPrefixUsage) {
@@ -1083,7 +1117,7 @@ TEST_F(ExpressionDateFromStringTest, EscapeCharacterAllowsPrefixUsage) {
<< "format"
<< "%Y %% %m %% %d"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-01-01T00:00:00.000Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-01-01T00:00:00.000Z", dateExp->evaluate({}, &expCtx->variables).toString());
}
@@ -1095,21 +1129,21 @@ TEST_F(ExpressionDateFromStringTest, EvaluatesToNullIfFormatIsNullish) {
<< "format"
<< BSONNULL));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "1/1/2017"
<< "format"
<< "$missing"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "1/1/2017"
<< "format"
<< BSONUndefined));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateFromStringTest, ReadWithUTCOffset) {
@@ -1120,35 +1154,35 @@ TEST_F(ExpressionDateFromStringTest, ReadWithUTCOffset) {
<< "timezone"
<< "-01:00"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T11:47:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T11:47:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-28T10:47:52.912"
<< "timezone"
<< "+01:00"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T09:47:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T09:47:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-28T10:47:52.912"
<< "timezone"
<< "+0445"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T06:02:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T06:02:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "2017-07-28T10:47:52.912"
<< "timezone"
<< "+10:45"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T00:02:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T00:02:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "1945-07-28T10:47:52.912"
<< "timezone"
<< "-08:00"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("1945-07-28T18:47:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("1945-07-28T18:47:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
}
TEST_F(ExpressionDateFromStringTest, ConvertStringWithUTCOffsetAndFormat) {
@@ -1161,7 +1195,7 @@ TEST_F(ExpressionDateFromStringTest, ConvertStringWithUTCOffsetAndFormat) {
<< "format"
<< "%H:%M:%S.%L on %m/%d/%Y"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T11:47:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T11:47:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "10:47:52.912 on 7/28/2017"
@@ -1170,7 +1204,7 @@ TEST_F(ExpressionDateFromStringTest, ConvertStringWithUTCOffsetAndFormat) {
<< "format"
<< "%H:%M:%S.%L on %m/%d/%Y"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-07-28T09:47:52.912Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-07-28T09:47:52.912Z", dateExp->evaluate({}, &expCtx->variables).toString());
}
TEST_F(ExpressionDateFromStringTest, ConvertStringWithISODateFormat) {
@@ -1181,7 +1215,7 @@ TEST_F(ExpressionDateFromStringTest, ConvertStringWithISODateFormat) {
<< "format"
<< "Day %u Week %V Year %G"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2018-01-07T00:00:00.000Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2018-01-07T00:00:00.000Z", dateExp->evaluate({}, &expCtx->variables).toString());
// Week and day of week default to '1' if not specified.
spec = BSON("$dateFromString" << BSON("dateString"
@@ -1189,14 +1223,14 @@ TEST_F(ExpressionDateFromStringTest, ConvertStringWithISODateFormat) {
<< "format"
<< "Week %V Year %G"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2018-01-01T00:00:00.000Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2018-01-01T00:00:00.000Z", dateExp->evaluate({}, &expCtx->variables).toString());
spec = BSON("$dateFromString" << BSON("dateString"
<< "Day 7 Year 2017"
<< "format"
<< "Day %u Year %G"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2017-01-08T00:00:00.000Z", dateExp->evaluate(Document{}).toString());
+ ASSERT_EQ("2017-01-08T00:00:00.000Z", dateExp->evaluate({}, &expCtx->variables).toString());
}
TEST_F(ExpressionDateFromStringTest, ReturnsOnNullForNullishInput) {
@@ -1205,25 +1239,25 @@ TEST_F(ExpressionDateFromStringTest, ReturnsOnNullForNullishInput) {
auto spec = BSON("$dateFromString" << BSON("dateString" << BSONNULL << "onNull"
<< "Null default"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "$missing"
<< "onNull"
<< "Null default"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "$missing"
<< "onNull"
<< "$alsoMissing"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString" << BSONNULL << "onNull" << BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateFromStringTest, InvalidFormatTakesPrecedenceOverOnNull) {
@@ -1234,14 +1268,14 @@ TEST_F(ExpressionDateFromStringTest, InvalidFormatTakesPrecedenceOverOnNull) {
<< "format"
<< 5));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40684);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40684);
spec = BSON("$dateFromString" << BSON("dateString" << BSONNULL << "onNull"
<< "Null default"
<< "format"
<< "%"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 18535);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 18535);
}
TEST_F(ExpressionDateFromStringTest, InvalidFormatTakesPrecedenceOverOnError) {
@@ -1254,14 +1288,14 @@ TEST_F(ExpressionDateFromStringTest, InvalidFormatTakesPrecedenceOverOnError) {
<< "format"
<< 5));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40684);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40684);
spec = BSON("$dateFromString" << BSON("dateString" << 5 << "onError"
<< "Not used default"
<< "format"
<< "%"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 18535);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 18535);
}
TEST_F(ExpressionDateFromStringTest, InvalidTimezoneTakesPrecedenceOverOnNull) {
@@ -1272,14 +1306,14 @@ TEST_F(ExpressionDateFromStringTest, InvalidTimezoneTakesPrecedenceOverOnNull) {
<< "timezone"
<< 5));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40517);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40517);
spec = BSON("$dateFromString" << BSON("dateString" << BSONNULL << "onNull"
<< "Null default"
<< "timezone"
<< "invalid timezone string"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40485);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40485);
}
TEST_F(ExpressionDateFromStringTest, InvalidTimezoneTakesPrecedenceOverOnError) {
@@ -1292,14 +1326,14 @@ TEST_F(ExpressionDateFromStringTest, InvalidTimezoneTakesPrecedenceOverOnError)
<< "timezone"
<< 5));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40517);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40517);
spec = BSON("$dateFromString" << BSON("dateString" << 5 << "onError"
<< "On error default"
<< "timezone"
<< "invalid timezone string"));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_THROWS_CODE(dateExp->evaluate({}), AssertionException, 40485);
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 40485);
}
TEST_F(ExpressionDateFromStringTest, OnNullTakesPrecedenceOverOtherNullishParameters) {
@@ -1310,14 +1344,14 @@ TEST_F(ExpressionDateFromStringTest, OnNullTakesPrecedenceOverOtherNullishParame
<< "timezone"
<< BSONNULL));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString" << BSONNULL << "onNull"
<< "Null default"
<< "format"
<< BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Null default"_sd), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateFromStringTest, OnNullOnlyUsedIfInputStringIsNullish) {
@@ -1330,7 +1364,7 @@ TEST_F(ExpressionDateFromStringTest, OnNullOnlyUsedIfInputStringIsNullish) {
<< "timezone"
<< BSONNULL));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
spec = BSON("$dateFromString" << BSON("dateString"
<< "2018-02-14"
@@ -1339,7 +1373,7 @@ TEST_F(ExpressionDateFromStringTest, OnNullOnlyUsedIfInputStringIsNullish) {
<< "format"
<< BSONNULL));
dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value(BSONNULL), dateExp->evaluate({}, &expCtx->variables));
}
TEST_F(ExpressionDateFromStringTest, ReturnsOnErrorForParseFailures) {
@@ -1351,7 +1385,7 @@ TEST_F(ExpressionDateFromStringTest, ReturnsOnErrorForParseFailures) {
auto spec = BSON("$dateFromString" << BSON("dateString" << date << "onError"
<< "Error default"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Error default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Error default"_sd), dateExp->evaluate({}, &expCtx->variables));
}
}
@@ -1365,7 +1399,7 @@ TEST_F(ExpressionDateFromStringTest, ReturnsOnErrorForFormatMismatch) {
BSON("$dateFromString" << BSON("dateString" << date << "format" << format << "onError"
<< "Error default"));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_VALUE_EQ(Value("Error default"_sd), dateExp->evaluate(Document{}));
+ ASSERT_VALUE_EQ(Value("Error default"_sd), dateExp->evaluate({}, &expCtx->variables));
}
}
@@ -1377,9 +1411,10 @@ TEST_F(ExpressionDateFromStringTest, OnNullEvaluatedLazily) {
<< "onNull"
<< BSON("$divide" << BSON_ARRAY(1 << 0))));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2018-02-14T00:00:00.000Z",
- dateExp->evaluate(Document{{"date", "2018-02-14"_sd}}).toString());
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{}), AssertionException, 16608);
+ ASSERT_EQ(
+ "2018-02-14T00:00:00.000Z",
+ dateExp->evaluate(Document{{"date", "2018-02-14"_sd}}, &expCtx->variables).toString());
+ ASSERT_THROWS_CODE(dateExp->evaluate({}, &expCtx->variables), AssertionException, 16608);
}
TEST_F(ExpressionDateFromStringTest, OnErrorEvaluatedLazily) {
@@ -1390,9 +1425,11 @@ TEST_F(ExpressionDateFromStringTest, OnErrorEvaluatedLazily) {
<< "onError"
<< BSON("$divide" << BSON_ARRAY(1 << 0))));
auto dateExp = Expression::parseExpression(expCtx, spec, expCtx->variablesParseState);
- ASSERT_EQ("2018-02-14T00:00:00.000Z",
- dateExp->evaluate(Document{{"date", "2018-02-14"_sd}}).toString());
- ASSERT_THROWS_CODE(dateExp->evaluate(Document{{"date", 5}}), AssertionException, 16608);
+ ASSERT_EQ(
+ "2018-02-14T00:00:00.000Z",
+ dateExp->evaluate(Document{{"date", "2018-02-14"_sd}}, &expCtx->variables).toString());
+ ASSERT_THROWS_CODE(
+ dateExp->evaluate(Document{{"date", 5}}, &expCtx->variables), AssertionException, 16608);
}
} // namespace ExpressionDateFromStringTest
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index 029320c1b2f..8552a8137cf 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -65,7 +65,7 @@ static Value evaluateExpression(const string& expressionName,
VariablesParseState vps = expCtx->variablesParseState;
const BSONObj obj = BSON(expressionName << ImplicitValue::convertToValue(operands));
auto expression = Expression::parseExpression(expCtx, obj, vps);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate({}, &expCtx->variables);
return result;
}
@@ -78,7 +78,7 @@ static Value evaluateNamedArgExpression(const string& expressionName, const Docu
VariablesParseState vps = expCtx->variablesParseState;
const BSONObj obj = BSON(expressionName << operand);
auto expression = Expression::parseExpression(expCtx, obj, vps);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate({}, &expCtx->variables);
return result;
}
@@ -175,8 +175,9 @@ class ExpressionNaryTestOneArg : public ExpressionBaseTest {
public:
virtual void assertEvaluates(Value input, Value output) {
addOperand(_expr, input);
- ASSERT_VALUE_EQ(output, _expr->evaluate(Document()));
- ASSERT_EQUALS(output.getType(), _expr->evaluate(Document()).getType());
+ ASSERT_VALUE_EQ(output, _expr->evaluate({}, &_expr->getExpressionContext()->variables));
+ ASSERT_EQUALS(output.getType(),
+ _expr->evaluate({}, &_expr->getExpressionContext()->variables).getType());
}
intrusive_ptr<ExpressionNary> _expr;
@@ -187,8 +188,9 @@ public:
virtual void assertEvaluates(Value input1, Value input2, Value output) {
addOperand(_expr, input1);
addOperand(_expr, input2);
- ASSERT_VALUE_EQ(output, _expr->evaluate(Document()));
- ASSERT_EQUALS(output.getType(), _expr->evaluate(Document()).getType());
+ ASSERT_VALUE_EQ(output, _expr->evaluate({}, &_expr->getExpressionContext()->variables));
+ ASSERT_EQUALS(output.getType(),
+ _expr->evaluate({}, &_expr->getExpressionContext()->variables).getType());
}
intrusive_ptr<ExpressionNary> _expr;
@@ -199,13 +201,13 @@ public:
/** A dummy child of ExpressionNary used for testing. */
class Testable : public ExpressionNary {
public:
- virtual Value evaluate(const Document& root) const {
+ virtual Value evaluate(const Document& root, Variables* variables) const {
// Just put all the values in a list.
// By default, this is not associative/commutative so the results will change if
// instantiated as commutative or associative and operations are reordered.
vector<Value> values;
for (auto&& child : _children)
- values.push_back(child->evaluate(root));
+ values.push_back(child->evaluate(root, variables));
return Value(values);
}
@@ -1380,7 +1382,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<ExpressionNary> expression = new ExpressionAdd(expCtx);
populateOperands(expression);
- ASSERT_BSONOBJ_EQ(expectedResult(), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(expectedResult(), toBson(expression->evaluate({}, &expCtx->variables)));
}
protected:
@@ -1396,7 +1398,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<ExpressionNary> expression = new ExpressionAdd(expCtx);
expression->addOperand(ExpressionConstant::create(expCtx, Value(2)));
- ASSERT_BSONOBJ_EQ(BSON("" << 2), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(BSON("" << 2), toBson(expression->evaluate({}, &expCtx->variables)));
}
};
@@ -1415,7 +1417,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<ExpressionNary> expression = new ExpressionAdd(expCtx);
expression->addOperand(ExpressionConstant::create(expCtx, Value("a"_sd)));
- ASSERT_THROWS(expression->evaluate(Document()), AssertionException);
+ ASSERT_THROWS(expression->evaluate({}, &expCtx->variables), AssertionException);
}
};
@@ -1426,7 +1428,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<ExpressionNary> expression = new ExpressionAdd(expCtx);
expression->addOperand(ExpressionConstant::create(expCtx, Value(true)));
- ASSERT_THROWS(expression->evaluate(Document()), AssertionException);
+ ASSERT_THROWS(expression->evaluate({}, &expCtx->variables), AssertionException);
}
};
@@ -1665,11 +1667,13 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
- toBson(expression->evaluate(fromBson(BSON("a" << 1)))));
+ ASSERT_BSONOBJ_EQ(
+ BSON("" << expectedResult()),
+ toBson(expression->evaluate(fromBson(BSON("a" << 1)), &expCtx->variables)));
intrusive_ptr<Expression> optimized = expression->optimize();
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
- toBson(optimized->evaluate(fromBson(BSON("a" << 1)))));
+ ASSERT_BSONOBJ_EQ(
+ BSON("" << expectedResult()),
+ toBson(optimized->evaluate(fromBson(BSON("a" << 1)), &expCtx->variables)));
}
protected:
@@ -1960,7 +1964,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> nested = ExpressionConstant::create(expCtx, Value(5));
intrusive_ptr<Expression> expression = ExpressionCoerceToBool::create(expCtx, nested);
- ASSERT(expression->evaluate(Document()).getBool());
+ ASSERT(expression->evaluate({}, &expCtx->variables).getBool());
}
};
@@ -1971,7 +1975,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> nested = ExpressionConstant::create(expCtx, Value(0));
intrusive_ptr<Expression> expression = ExpressionCoerceToBool::create(expCtx, nested);
- ASSERT(!expression->evaluate(Document()).getBool());
+ ASSERT(!expression->evaluate({}, &expCtx->variables).getBool());
}
};
@@ -2079,10 +2083,10 @@ public:
// Check expression spec round trip.
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
// Check evaluation result.
- ASSERT_BSONOBJ_EQ(expectedResult(), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(expectedResult(), toBson(expression->evaluate({}, &expCtx->variables)));
// Check that the result is the same after optimizing.
intrusive_ptr<Expression> optimized = expression->optimize();
- ASSERT_BSONOBJ_EQ(expectedResult(), toBson(optimized->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(expectedResult(), toBson(optimized->evaluate({}, &expCtx->variables)));
}
protected:
@@ -2319,7 +2323,7 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
- ASSERT_VALUE_EQ(expression->evaluate(Document()), Value(true));
+ ASSERT_VALUE_EQ(expression->evaluate({}, &expCtx->variables), Value(true));
}
};
@@ -2452,7 +2456,7 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionConstant::create(expCtx, Value(5));
- assertBinaryEqual(BSON("" << 5), toBson(expression->evaluate(Document())));
+ assertBinaryEqual(BSON("" << 5), toBson(expression->evaluate({}, &expCtx->variables)));
}
};
@@ -2468,7 +2472,7 @@ public:
intrusive_ptr<Expression> expression = ExpressionConstant::parse(expCtx, specElement, vps);
assertBinaryEqual(BSON(""
<< "foo"),
- toBson(expression->evaluate(Document())));
+ toBson(expression->evaluate({}, &expCtx->variables)));
}
};
@@ -2534,7 +2538,9 @@ private:
TEST(ExpressionConstantTest, ConstantOfValueMissingRemovesField) {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionConstant::create(expCtx, Value());
- assertBinaryEqual(BSONObj(), toBson(expression->evaluate(Document{{"foo", Value("bar"_sd)}})));
+ assertBinaryEqual(
+ BSONObj(),
+ toBson(expression->evaluate(Document{{"foo", Value("bar"_sd)}}, &expCtx->variables)));
}
TEST(ExpressionConstantTest, ConstantOfValueMissingSerializesToRemoveSystemVar) {
@@ -2637,11 +2643,11 @@ TEST(ExpressionPowTest, ThrowsWhenBaseZeroAndExpNegative) {
VariablesParseState vps = expCtx->variablesParseState;
const auto expr = Expression::parseExpression(expCtx, BSON("$pow" << BSON_ARRAY(0 << -5)), vps);
- ASSERT_THROWS([&] { expr->evaluate(Document()); }(), AssertionException);
+ ASSERT_THROWS([&] { expr->evaluate({}, &expCtx->variables); }(), AssertionException);
const auto exprWithLong =
Expression::parseExpression(expCtx, BSON("$pow" << BSON_ARRAY(0LL << -5LL)), vps);
- ASSERT_THROWS([&] { expr->evaluate(Document()); }(), AssertionException);
+ ASSERT_THROWS([&] { expr->evaluate({}, &expCtx->variables); }(), AssertionException);
}
TEST(ExpressionPowTest, LargeExponentValuesWithBaseOfOne) {
@@ -2792,21 +2798,35 @@ TEST(ExpressionIndexOfArray,
fromjson("{ $indexOfArray : [ [0, 1, 2, 3, 4, 5, 'val'] , '$x'] }"),
expCtx->variablesParseState);
auto optimizedIndexOfArray = expIndexOfArray->optimize();
- ASSERT_VALUE_EQ(Value(0), optimizedIndexOfArray->evaluate(Document{{"x", 0}}));
- ASSERT_VALUE_EQ(Value(1), optimizedIndexOfArray->evaluate(Document{{"x", 1}}));
- ASSERT_VALUE_EQ(Value(2), optimizedIndexOfArray->evaluate(Document{{"x", 2}}));
- ASSERT_VALUE_EQ(Value(3), optimizedIndexOfArray->evaluate(Document{{"x", 3}}));
- ASSERT_VALUE_EQ(Value(4), optimizedIndexOfArray->evaluate(Document{{"x", 4}}));
- ASSERT_VALUE_EQ(Value(5), optimizedIndexOfArray->evaluate(Document{{"x", 5}}));
- ASSERT_VALUE_EQ(Value(6), optimizedIndexOfArray->evaluate(Document{{"x", string("val")}}));
+ ASSERT_VALUE_EQ(Value(0),
+ optimizedIndexOfArray->evaluate(Document{{"x", 0}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(1),
+ optimizedIndexOfArray->evaluate(Document{{"x", 1}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(2),
+ optimizedIndexOfArray->evaluate(Document{{"x", 2}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(3),
+ optimizedIndexOfArray->evaluate(Document{{"x", 3}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(4),
+ optimizedIndexOfArray->evaluate(Document{{"x", 4}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(5),
+ optimizedIndexOfArray->evaluate(Document{{"x", 5}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(
+ Value(6),
+ optimizedIndexOfArray->evaluate(Document{{"x", string("val")}}, &expCtx->variables));
auto optimizedIndexNotFound = optimizedIndexOfArray->optimize();
// Should evaluate to -1 if not found.
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexNotFound->evaluate(Document{{"x", 10}}));
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexNotFound->evaluate(Document{{"x", 100}}));
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexNotFound->evaluate(Document{{"x", 1000}}));
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexNotFound->evaluate(Document{{"x", string("string")}}));
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexNotFound->evaluate(Document{{"x", -1}}));
+ ASSERT_VALUE_EQ(Value(-1),
+ optimizedIndexNotFound->evaluate(Document{{"x", 10}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(-1),
+ optimizedIndexNotFound->evaluate(Document{{"x", 100}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(-1),
+ optimizedIndexNotFound->evaluate(Document{{"x", 1000}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(
+ Value(-1),
+ optimizedIndexNotFound->evaluate(Document{{"x", string("string")}}, &expCtx->variables));
+ ASSERT_VALUE_EQ(Value(-1),
+ optimizedIndexNotFound->evaluate(Document{{"x", -1}}, &expCtx->variables));
}
TEST(ExpressionIndexOfArray,
@@ -2819,10 +2839,12 @@ TEST(ExpressionIndexOfArray,
fromjson("{ $indexOfArray : [ [0, 1, 2, 3, 4, 5] , '$x', 3, 5] }"),
expCtx->variablesParseState);
auto optimizedIndexOfArray = expIndexOfArray->optimize();
- ASSERT_VALUE_EQ(Value(4), optimizedIndexOfArray->evaluate(Document{{"x", 4}}));
+ ASSERT_VALUE_EQ(Value(4),
+ optimizedIndexOfArray->evaluate(Document{{"x", 4}}, &expCtx->variables));
// Should evaluate to -1 if not found in range.
- ASSERT_VALUE_EQ(Value(-1), optimizedIndexOfArray->evaluate(Document{{"x", 0}}));
+ ASSERT_VALUE_EQ(Value(-1),
+ optimizedIndexOfArray->evaluate(Document{{"x", 0}}, &expCtx->variables));
}
TEST(ExpressionIndexOfArray,
@@ -2835,8 +2857,9 @@ TEST(ExpressionIndexOfArray,
fromjson("{ $indexOfArray : [ [0, 1, 2, 2, 3, 4, 5] , '$x'] }"),
expCtx->variablesParseState);
auto optimizedIndexOfArrayWithDuplicateValues = expIndexOfArrayWithDuplicateValues->optimize();
- ASSERT_VALUE_EQ(Value(2),
- optimizedIndexOfArrayWithDuplicateValues->evaluate(Document{{"x", 2}}));
+ ASSERT_VALUE_EQ(
+ Value(2),
+ optimizedIndexOfArrayWithDuplicateValues->evaluate(Document{{"x", 2}}, &expCtx->variables));
// Duplicate Values in a range.
auto expIndexInRangeWithhDuplicateValues = Expression::parseExpression(
expCtx,
@@ -2845,8 +2868,9 @@ TEST(ExpressionIndexOfArray,
expCtx->variablesParseState);
auto optimizedIndexInRangeWithDuplcateValues = expIndexInRangeWithhDuplicateValues->optimize();
// Should evaluate to 4.
- ASSERT_VALUE_EQ(Value(4),
- optimizedIndexInRangeWithDuplcateValues->evaluate(Document{{"x", 2}}));
+ ASSERT_VALUE_EQ(
+ Value(4),
+ optimizedIndexInRangeWithDuplcateValues->evaluate(Document{{"x", 2}}, &expCtx->variables));
}
namespace FieldPath {
@@ -2885,7 +2909,9 @@ TEST(FieldPath, RemoveOptimizesToMissingValue) {
auto optimizedExpr = expression->optimize();
- ASSERT_VALUE_EQ(Value(), optimizedExpr->evaluate(Document(BSON("x" << BSON("y" << 123)))));
+ ASSERT_VALUE_EQ(
+ Value(),
+ optimizedExpr->evaluate(Document(BSON("x" << BSON("y" << 123))), &expCtx->variables));
}
TEST(FieldPath, NoOptimizationOnNormalPath) {
@@ -3007,7 +3033,7 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a");
- assertBinaryEqual(fromjson("{}"), toBson(expression->evaluate(Document())));
+ assertBinaryEqual(fromjson("{}"), toBson(expression->evaluate({}, &expCtx->variables)));
}
};
@@ -3017,8 +3043,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a");
- assertBinaryEqual(fromjson("{'':123}"),
- toBson(expression->evaluate(fromBson(BSON("a" << 123)))));
+ assertBinaryEqual(
+ fromjson("{'':123}"),
+ toBson(expression->evaluate(fromBson(BSON("a" << 123)), &expCtx->variables)));
}
};
@@ -3028,8 +3055,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:null}")))));
+ assertBinaryEqual(
+ fromjson("{}"),
+ toBson(expression->evaluate(fromBson(fromjson("{a:null}")), &expCtx->variables)));
}
};
@@ -3039,8 +3067,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:undefined}")))));
+ assertBinaryEqual(
+ fromjson("{}"),
+ toBson(expression->evaluate(fromBson(fromjson("{a:undefined}")), &expCtx->variables)));
}
};
@@ -3050,8 +3079,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{}"),
- toBson(expression->evaluate(fromBson(fromjson("{z:1}")))));
+ assertBinaryEqual(
+ fromjson("{}"),
+ toBson(expression->evaluate(fromBson(fromjson("{z:1}")), &expCtx->variables)));
}
};
@@ -3061,7 +3091,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{}"), toBson(expression->evaluate(fromBson(BSON("a" << 2)))));
+ assertBinaryEqual(
+ fromjson("{}"),
+ toBson(expression->evaluate(fromBson(BSON("a" << 2)), &expCtx->variables)));
}
};
@@ -3072,7 +3104,8 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
assertBinaryEqual(BSON("" << 55),
- toBson(expression->evaluate(fromBson(BSON("a" << BSON("b" << 55))))));
+ toBson(expression->evaluate(fromBson(BSON("a" << BSON("b" << 55))),
+ &expCtx->variables)));
}
};
@@ -3082,8 +3115,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{}"),
- toBson(expression->evaluate(fromBson(BSON("a" << BSONObj())))));
+ assertBinaryEqual(
+ fromjson("{}"),
+ toBson(expression->evaluate(fromBson(BSON("a" << BSONObj())), &expCtx->variables)));
}
};
@@ -3093,8 +3127,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(BSON("" << BSONArray()),
- toBson(expression->evaluate(fromBson(BSON("a" << BSONArray())))));
+ assertBinaryEqual(
+ BSON("" << BSONArray()),
+ toBson(expression->evaluate(fromBson(BSON("a" << BSONArray())), &expCtx->variables)));
}
};
@@ -3104,8 +3139,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{'':[]}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:[null]}")))));
+ assertBinaryEqual(
+ fromjson("{'':[]}"),
+ toBson(expression->evaluate(fromBson(fromjson("{a:[null]}")), &expCtx->variables)));
}
};
@@ -3116,7 +3152,8 @@ public:
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
assertBinaryEqual(fromjson("{'':[]}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:[undefined]}")))));
+ toBson(expression->evaluate(fromBson(fromjson("{a:[undefined]}")),
+ &expCtx->variables)));
}
};
@@ -3126,8 +3163,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{'':[]}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:[1]}")))));
+ assertBinaryEqual(
+ fromjson("{'':[]}"),
+ toBson(expression->evaluate(fromBson(fromjson("{a:[1]}")), &expCtx->variables)));
}
};
@@ -3137,8 +3175,9 @@ public:
void run() {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
- assertBinaryEqual(fromjson("{'':[9]}"),
- toBson(expression->evaluate(fromBson(fromjson("{a:[{b:9}]}")))));
+ assertBinaryEqual(
+ fromjson("{'':[9]}"),
+ toBson(expression->evaluate(fromBson(fromjson("{a:[{b:9}]}")), &expCtx->variables)));
}
};
@@ -3150,7 +3189,8 @@ public:
intrusive_ptr<Expression> expression = ExpressionFieldPath::create(expCtx, "a.b");
assertBinaryEqual(fromjson("{'':[9,20]}"),
toBson(expression->evaluate(
- fromBson(fromjson("{a:[{b:9},null,undefined,{g:4},{b:20},{}]}")))));
+ fromBson(fromjson("{a:[{b:9},null,undefined,{g:4},{b:20},{}]}")),
+ &expCtx->variables)));
}
};
@@ -3165,7 +3205,8 @@ public:
"{b:{c:3}},"
"{b:[{c:4}]},"
"{b:[{c:[5]}]},"
- "{b:{c:[6,7]}}]}")))));
+ "{b:{c:[6,7]}}]}")),
+ &expCtx->variables)));
}
};
@@ -3359,19 +3400,22 @@ auto expressionObjectCreateHelper(
TEST(ExpressionObjectEvaluate, EmptyObjectShouldEvaluateToEmptyDocument) {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
auto object = expressionObjectCreateHelper(expCtx, {});
- ASSERT_VALUE_EQ(Value(Document()), object->evaluate(Document()));
- ASSERT_VALUE_EQ(Value(Document()), object->evaluate(Document{{"a", 1}}));
- ASSERT_VALUE_EQ(Value(Document()), object->evaluate(Document{{"_id", "ID"_sd}}));
+ ASSERT_VALUE_EQ(Value(Document()), object->evaluate(Document(), &(expCtx->variables)));
+ ASSERT_VALUE_EQ(Value(Document()), object->evaluate(Document{{"a", 1}}, &(expCtx->variables)));
+ ASSERT_VALUE_EQ(Value(Document()),
+ object->evaluate(Document{{"_id", "ID"_sd}}, &(expCtx->variables)));
}
TEST(ExpressionObjectEvaluate, ShouldEvaluateEachField) {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
auto object =
expressionObjectCreateHelper(expCtx, {{"a", makeConstant(1)}, {"b", makeConstant(5)}});
- ASSERT_VALUE_EQ(Value(Document{{"a", 1}, {"b", 5}}), object->evaluate(Document()));
- ASSERT_VALUE_EQ(Value(Document{{"a", 1}, {"b", 5}}), object->evaluate(Document{{"a", 1}}));
ASSERT_VALUE_EQ(Value(Document{{"a", 1}, {"b", 5}}),
- object->evaluate(Document{{"_id", "ID"_sd}}));
+ object->evaluate(Document(), &(expCtx->variables)));
+ ASSERT_VALUE_EQ(Value(Document{{"a", 1}, {"b", 5}}),
+ object->evaluate(Document{{"a", 1}}, &(expCtx->variables)));
+ ASSERT_VALUE_EQ(Value(Document{{"a", 1}, {"b", 5}}),
+ object->evaluate(Document{{"_id", "ID"_sd}}, &(expCtx->variables)));
}
TEST(ExpressionObjectEvaluate, OrderOfFieldsInOutputShouldMatchOrderInSpecification) {
@@ -3382,7 +3426,8 @@ TEST(ExpressionObjectEvaluate, OrderOfFieldsInOutputShouldMatchOrderInSpecificat
{"c", ExpressionFieldPath::create(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}}));
+ object->evaluate(Document{{"c", "C"_sd}, {"a", "A"_sd}, {"b", "B"_sd}, {"_id", "ID"_sd}},
+ &(expCtx->variables)));
}
TEST(ExpressionObjectEvaluate, ShouldRemoveFieldsThatHaveMissingValues) {
@@ -3391,8 +3436,8 @@ TEST(ExpressionObjectEvaluate, ShouldRemoveFieldsThatHaveMissingValues) {
expressionObjectCreateHelper(expCtx,
{{"a", ExpressionFieldPath::create(expCtx, "a.b")},
{"b", ExpressionFieldPath::create(expCtx, "missing")}});
- ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document()));
- ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document{{"a", 1}}));
+ ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document(), &(expCtx->variables)));
+ ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document{{"a", 1}}, &(expCtx->variables)));
}
TEST(ExpressionObjectEvaluate, ShouldEvaluateFieldsWithinNestedObject) {
@@ -3403,20 +3448,21 @@ TEST(ExpressionObjectEvaluate, ShouldEvaluateFieldsWithinNestedObject) {
expressionObjectCreateHelper(
expCtx,
{{"b", makeConstant(1)}, {"c", ExpressionFieldPath::create(expCtx, "_id")}})}});
- ASSERT_VALUE_EQ(Value(Document{{"a", Document{{"b", 1}}}}), object->evaluate(Document()));
+ 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}}}}),
- object->evaluate(Document{{"_id", "ID"_sd}}));
+ object->evaluate(Document{{"_id", "ID"_sd}}, &(expCtx->variables)));
}
TEST(ExpressionObjectEvaluate, ShouldEvaluateToEmptyDocumentIfAllFieldsAreMissing) {
intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
auto object = expressionObjectCreateHelper(
expCtx, {{"a", ExpressionFieldPath::create(expCtx, "missing")}});
- ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document()));
+ ASSERT_VALUE_EQ(Value(Document{}), object->evaluate(Document(), &(expCtx->variables)));
auto objectWithNestedObject = expressionObjectCreateHelper(expCtx, {{"nested", object}});
ASSERT_VALUE_EQ(Value(Document{{"nested", Document{}}}),
- objectWithNestedObject->evaluate(Document()));
+ objectWithNestedObject->evaluate(Document(), &(expCtx->variables)));
}
//
@@ -3519,7 +3565,8 @@ TEST(ExpressionObjectOptimizations, OptimizingAnObjectShouldOptimizeSubExpressio
auto optimized = object->optimize();
auto optimizedObject = dynamic_cast<ExpressionConstant*>(optimized.get());
ASSERT_TRUE(optimizedObject);
- ASSERT_VALUE_EQ(optimizedObject->evaluate(Document()), Value(BSON("a" << 3)));
+ ASSERT_VALUE_EQ(optimizedObject->evaluate(Document(), &(expCtx->variables)),
+ Value(BSON("a" << 3)));
};
TEST(ExpressionObjectOptimizations,
@@ -3552,7 +3599,7 @@ TEST(ExpressionObjectOptimizations,
auto optimizedWithConstant = expressionWithConstantObject->optimize();
auto optimizedObject = dynamic_cast<ExpressionConstant*>(optimizedWithConstant.get());
ASSERT_TRUE(optimizedObject);
- ASSERT_VALUE_EQ(optimizedObject->evaluate(Document()),
+ ASSERT_VALUE_EQ(optimizedObject->evaluate(Document(), &expCtx->variables),
Value(BSON("willBeConstant" << 3 << "alreadyConstant"
<< "string")));
};
@@ -3571,11 +3618,13 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
- toBson(expression->evaluate(fromBson(BSON("a" << 1)))));
+ ASSERT_BSONOBJ_EQ(
+ BSON("" << expectedResult()),
+ toBson(expression->evaluate(fromBson(BSON("a" << 1)), &expCtx->variables)));
intrusive_ptr<Expression> optimized = expression->optimize();
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
- toBson(optimized->evaluate(fromBson(BSON("a" << 1)))));
+ ASSERT_BSONOBJ_EQ(
+ BSON("" << expectedResult()),
+ toBson(optimized->evaluate(fromBson(BSON("a" << 1)), &expCtx->variables)));
}
protected:
@@ -4083,7 +4132,7 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
const intrusive_ptr<Expression> expr =
Expression::parseExpression(expCtx, obj, vps);
- Value result = expr->evaluate(Document());
+ Value result = expr->evaluate({}, &expCtx->variables);
if (result.getType() == Array) {
result = sortSet(result);
}
@@ -4110,7 +4159,7 @@ public:
// same
const intrusive_ptr<Expression> expr =
Expression::parseExpression(expCtx, obj, vps);
- expr->evaluate(Document());
+ expr->evaluate({}, &expCtx->variables);
}(),
AssertionException);
}
@@ -4392,7 +4441,8 @@ private:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(BSON("" << expectedResult),
+ toBson(expression->evaluate({}, &expCtx->variables)));
}
};
@@ -4518,7 +4568,8 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
+ toBson(expression->evaluate({}, &expCtx->variables)));
}
protected:
@@ -4636,7 +4687,7 @@ TEST(ExpressionSubstrTest, ThrowsWithNegativeStart) {
const auto str = "abcdef"_sd;
const auto expr =
Expression::parseExpression(expCtx, BSON("$substrCP" << BSON_ARRAY(str << -5 << 1)), vps);
- ASSERT_THROWS([&] { expr->evaluate(Document()); }(), AssertionException);
+ ASSERT_THROWS([&] { expr->evaluate({}, &expCtx->variables); }(), AssertionException);
}
} // namespace Substr
@@ -4650,7 +4701,7 @@ TEST(ExpressionSubstrCPTest, DoesThrowWithBadContinuationByte) {
const auto continuationByte = "\x80\x00"_sd;
const auto expr = Expression::parseExpression(
expCtx, BSON("$substrCP" << BSON_ARRAY(continuationByte << 0 << 1)), vps);
- ASSERT_THROWS([&] { expr->evaluate(Document()); }(), AssertionException);
+ ASSERT_THROWS([&] { expr->evaluate({}, &expCtx->variables); }(), AssertionException);
}
TEST(ExpressionSubstrCPTest, DoesThrowWithInvalidLeadingByte) {
@@ -4660,7 +4711,7 @@ TEST(ExpressionSubstrCPTest, DoesThrowWithInvalidLeadingByte) {
const auto leadingByte = "\xFF\x00"_sd;
const auto expr = Expression::parseExpression(
expCtx, BSON("$substrCP" << BSON_ARRAY(leadingByte << 0 << 1)), vps);
- ASSERT_THROWS([&] { expr->evaluate(Document()); }(), AssertionException);
+ ASSERT_THROWS([&] { expr->evaluate({}, &expCtx->variables); }(), AssertionException);
}
TEST(ExpressionSubstrCPTest, WithStandardValue) {
@@ -5110,7 +5161,7 @@ TEST(ExpressionTrimTest, TrimComparisonsShouldNotRespectCollation) {
<< "x")),
expCtx->variablesParseState);
- ASSERT_VALUE_EQ(trim->evaluate(Document()), Value("XX"_sd));
+ ASSERT_VALUE_EQ(trim->evaluate({}, &expCtx->variables), Value("XX"_sd));
}
TEST(ExpressionTrimTest, ShouldRejectInvalidUTFInCharsArgument) {
@@ -5383,7 +5434,7 @@ TEST(ExpressionTrimTest, DoesSerializeCorrectly) {
// Make sure we can re-parse it and evaluate it.
auto reparsedTrim = Expression::parseExpression(
expCtx, trim->serialize(false).getDocument().toBson(), expCtx->variablesParseState);
- ASSERT_VALUE_EQ(reparsedTrim->evaluate(Document()), Value("abc"_sd));
+ ASSERT_VALUE_EQ(reparsedTrim->evaluate({}, &expCtx->variables), Value("abc"_sd));
// Use $ltrim, and specify the 'chars' option.
trim = Expression::parseExpression(expCtx,
@@ -5399,7 +5450,8 @@ TEST(ExpressionTrimTest, DoesSerializeCorrectly) {
// Make sure we can re-parse it and evaluate it.
reparsedTrim = Expression::parseExpression(
expCtx, trim->serialize(false).getDocument().toBson(), expCtx->variablesParseState);
- ASSERT_VALUE_EQ(reparsedTrim->evaluate(Document{{"inputField", " , 4"_sd}, {"a", " ,"_sd}}),
+ ASSERT_VALUE_EQ(reparsedTrim->evaluate(Document{{"inputField", " , 4"_sd}, {"a", " ,"_sd}},
+ &expCtx->variables),
Value("4"_sd));
}
} // namespace Trim
@@ -5627,7 +5679,8 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
+ toBson(expression->evaluate({}, &expCtx->variables)));
}
protected:
@@ -5684,7 +5737,8 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
intrusive_ptr<Expression> expression = Expression::parseOperand(expCtx, specElement, vps);
ASSERT_BSONOBJ_EQ(constify(spec()), expressionToBson(expression));
- ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()), toBson(expression->evaluate(Document())));
+ ASSERT_BSONOBJ_EQ(BSON("" << expectedResult()),
+ toBson(expression->evaluate({}, &expCtx->variables)));
}
protected:
@@ -5746,7 +5800,7 @@ public:
VariablesParseState vps = expCtx->variablesParseState;
const intrusive_ptr<Expression> expr =
Expression::parseExpression(expCtx, obj, vps);
- const Value result = expr->evaluate(Document());
+ const Value result = expr->evaluate({}, &expCtx->variables);
if (ValueComparator().evaluate(result != expected)) {
string errMsg = str::stream()
<< "for expression " << field.first.toString() << " with argument "
@@ -5770,7 +5824,7 @@ public:
// same
const intrusive_ptr<Expression> expr =
Expression::parseExpression(expCtx, obj, vps);
- expr->evaluate(Document());
+ expr->evaluate({}, &expCtx->variables);
}(),
AssertionException);
}
@@ -6014,7 +6068,7 @@ TEST(ExpressionMetaTest, ExpressionMetaSearchScore) {
MutableDocument doc;
doc.setSearchScore(1.234);
- Value val = expressionMeta->evaluate(doc.freeze());
+ Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables);
ASSERT_EQ(val.getDouble(), 1.234);
}
@@ -6028,7 +6082,7 @@ TEST(ExpressionMetaTest, ExpressionMetaSearchHighlights) {
Document highlights = DOC("this part" << 1 << "is opaque to the server" << 1);
doc.setSearchHighlights(Value(highlights));
- Value val = expressionMeta->evaluate(doc.freeze());
+ Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables);
ASSERT_DOCUMENT_EQ(val.getDocument(), highlights);
}
} // namespace expression_meta_test
@@ -6038,8 +6092,9 @@ namespace ExpressionRegexTest {
class ExpressionRegexTest {
public:
template <typename ExpressionRegexSubClass>
- static intrusive_ptr<Expression> generateOptimizedExpression(const BSONObj& input) {
- intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ static intrusive_ptr<Expression> generateOptimizedExpression(
+ const BSONObj& input, intrusive_ptr<ExpressionContextForTest> expCtx) {
+
auto expression = ExpressionRegexSubClass::parse(
expCtx, input.firstElement(), expCtx->variablesParseState);
return expression->optimize();
@@ -6048,31 +6103,31 @@ public:
static void testAllExpressions(const BSONObj& input,
bool optimized,
const std::vector<Value>& expectedFindAllOutput) {
+
+ intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
{
// For $regexFindAll.
- auto expression = generateOptimizedExpression<ExpressionRegexFindAll>(input);
+ auto expression = generateOptimizedExpression<ExpressionRegexFindAll>(input, expCtx);
auto regexFindAllExpr = dynamic_cast<ExpressionRegexFindAll*>(expression.get());
ASSERT_EQ(regexFindAllExpr->hasConstantRegex(), optimized);
- Value output = regexFindAllExpr->evaluate(Document());
+ Value output = expression->evaluate({}, &expCtx->variables);
ASSERT_VALUE_EQ(output, Value(expectedFindAllOutput));
}
-
{
// For $regexFind.
- auto expression = generateOptimizedExpression<ExpressionRegexFind>(input);
+ auto expression = generateOptimizedExpression<ExpressionRegexFind>(input, expCtx);
auto regexFindExpr = dynamic_cast<ExpressionRegexFind*>(expression.get());
ASSERT_EQ(regexFindExpr->hasConstantRegex(), optimized);
- Value output = regexFindExpr->evaluate(Document());
+ Value output = expression->evaluate({}, &expCtx->variables);
ASSERT_VALUE_EQ(
output, expectedFindAllOutput.empty() ? Value(BSONNULL) : expectedFindAllOutput[0]);
}
-
{
// For $regexMatch.
- auto expression = generateOptimizedExpression<ExpressionRegexMatch>(input);
+ auto expression = generateOptimizedExpression<ExpressionRegexMatch>(input, expCtx);
auto regexMatchExpr = dynamic_cast<ExpressionRegexMatch*>(expression.get());
ASSERT_EQ(regexMatchExpr->hasConstantRegex(), optimized);
- Value output = regexMatchExpr->evaluate(Document());
+ Value output = expression->evaluate({}, &expCtx->variables);
ASSERT_VALUE_EQ(output, expectedFindAllOutput.empty() ? Value(false) : Value(true));
}
}
@@ -6380,14 +6435,14 @@ TEST(NowAndClusterTime, BasicTest) {
// $$NOW is the Date type.
{
auto expression = ExpressionFieldPath::parse(expCtx, "$$NOW", expCtx->variablesParseState);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate(Document(), &(expCtx->variables));
ASSERT_EQ(result.getType(), Date);
}
// $$CLUSTER_TIME is the timestamp type.
{
auto expression =
ExpressionFieldPath::parse(expCtx, "$$CLUSTER_TIME", expCtx->variablesParseState);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate(Document(), &(expCtx->variables));
ASSERT_EQ(result.getType(), bsonTimestamp);
}
@@ -6395,7 +6450,7 @@ TEST(NowAndClusterTime, BasicTest) {
{
auto expression = Expression::parseExpression(
expCtx, fromjson("{$eq: [\"$$NOW\", \"$$NOW\"]}"), expCtx->variablesParseState);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate(Document(), &(expCtx->variables));
ASSERT_VALUE_EQ(result, Value{true});
}
@@ -6405,7 +6460,7 @@ TEST(NowAndClusterTime, BasicTest) {
Expression::parseExpression(expCtx,
fromjson("{$eq: [\"$$CLUSTER_TIME\", \"$$CLUSTER_TIME\"]}"),
expCtx->variablesParseState);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate(Document(), &(expCtx->variables));
ASSERT_VALUE_EQ(result, Value{true});
}
diff --git a/src/mongo/db/pipeline/expression_trigonometric_test.cpp b/src/mongo/db/pipeline/expression_trigonometric_test.cpp
index 35756404dd4..49ea60e1f9b 100644
--- a/src/mongo/db/pipeline/expression_trigonometric_test.cpp
+++ b/src/mongo/db/pipeline/expression_trigonometric_test.cpp
@@ -58,7 +58,7 @@ static void assertEvaluates(const std::string& expressionName, Value input, Valu
auto obj = BSON(expressionName << BSON_ARRAY(input));
auto vps = expCtx->variablesParseState;
auto expression = Expression::parseExpression(expCtx, obj, vps);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate({}, &expCtx->variables);
ASSERT_EQUALS(result.getType(), output.getType());
assertApproxEq(result, output);
}
@@ -73,7 +73,7 @@ static void assertEvaluates(const std::string& expressionName,
auto obj = BSON(expressionName << BSON_ARRAY(input1 << input2));
auto vps = expCtx->variablesParseState;
auto expression = Expression::parseExpression(expCtx, obj, vps);
- Value result = expression->evaluate(Document());
+ Value result = expression->evaluate({}, &expCtx->variables);
ASSERT_EQUALS(result.getType(), output.getType());
assertApproxEq(result, output);
}
diff --git a/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp b/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp
index 3a033cc034f..aa622f9b014 100644
--- a/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp
+++ b/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp
@@ -81,7 +81,8 @@ Value GranularityRounderPowersOfTwo::roundUp(Value value) {
exp = Value(63 - countLeadingZeros64(number) + 1);
}
- return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document());
+ return ExpressionPow::create(getExpCtx(), Value(2), exp)
+ ->evaluate(Document(), &getExpCtx()->variables);
}
Value GranularityRounderPowersOfTwo::roundDown(Value value) {
@@ -113,7 +114,8 @@ Value GranularityRounderPowersOfTwo::roundDown(Value value) {
}
}
- return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document());
+ return ExpressionPow::create(getExpCtx(), Value(2), exp)
+ ->evaluate(Document(), &getExpCtx()->variables);
}
string GranularityRounderPowersOfTwo::getName() {
diff --git a/src/mongo/db/pipeline/parsed_aggregation_projection_node.cpp b/src/mongo/db/pipeline/parsed_aggregation_projection_node.cpp
index 18b6e243f09..65637d9144b 100644
--- a/src/mongo/db/pipeline/parsed_aggregation_projection_node.cpp
+++ b/src/mongo/db/pipeline/parsed_aggregation_projection_node.cpp
@@ -172,7 +172,10 @@ void ProjectionNode::applyExpressions(const Document& root, MutableDocument* out
} else {
auto expressionIt = _expressions.find(field);
invariant(expressionIt != _expressions.end());
- outputDoc->setField(field, expressionIt->second->evaluate(root));
+ outputDoc->setField(
+ field,
+ expressionIt->second->evaluate(
+ root, &expressionIt->second->getExpressionContext()->variables));
}
}
}