summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline
diff options
context:
space:
mode:
authorJames Wahlin <james.wahlin@10gen.com>2017-05-01 15:18:17 -0400
committerJames Wahlin <james.wahlin@10gen.com>2017-05-03 11:31:32 -0400
commitfff7292a4dec1eb30b36dfb79f6d933fbb1df6b7 (patch)
treef2693e48a453e42b90d8c5dc01373086a4d92c98 /src/mongo/db/pipeline
parent435d43b66f04fc12fdb4f1e115d1fe9558571334 (diff)
downloadmongo-fff7292a4dec1eb30b36dfb79f6d933fbb1df6b7.tar.gz
SERVER-28651 Pass agg Variables root doc via Expression::evaluate()
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r--src/mongo/db/pipeline/document_source_bucket_auto.cpp6
-rw-r--r--src/mongo/db/pipeline/document_source_graph_lookup.cpp5
-rw-r--r--src/mongo/db/pipeline/document_source_group.cpp31
-rw-r--r--src/mongo/db/pipeline/document_source_group.h2
-rw-r--r--src/mongo/db/pipeline/document_source_redact.cpp21
-rw-r--r--src/mongo/db/pipeline/document_source_redact.h4
-rw-r--r--src/mongo/db/pipeline/document_source_replace_root.cpp3
-rw-r--r--src/mongo/db/pipeline/document_source_sort.cpp5
-rw-r--r--src/mongo/db/pipeline/expression.cpp365
-rw-r--r--src/mongo/db/pipeline/expression.h172
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp4
-rw-r--r--src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp4
-rw-r--r--src/mongo/db/pipeline/parsed_add_fields.cpp8
-rw-r--r--src/mongo/db/pipeline/parsed_add_fields.h8
-rw-r--r--src/mongo/db/pipeline/parsed_inclusion_projection.cpp20
-rw-r--r--src/mongo/db/pipeline/parsed_inclusion_projection.h12
-rw-r--r--src/mongo/db/pipeline/variables.cpp10
-rw-r--r--src/mongo/db/pipeline/variables.h24
18 files changed, 316 insertions, 388 deletions
diff --git a/src/mongo/db/pipeline/document_source_bucket_auto.cpp b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
index a31e91ff845..3bd8ecc837f 100644
--- a/src/mongo/db/pipeline/document_source_bucket_auto.cpp
+++ b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
@@ -118,8 +118,7 @@ Value DocumentSourceBucketAuto::extractKey(const Document& doc) {
return Value(BSONNULL);
}
- pExpCtx->variables.setRoot(doc);
- Value key = _groupByExpression->evaluate();
+ Value key = _groupByExpression->evaluate(doc);
if (_granularityRounder) {
uassert(40258,
@@ -151,9 +150,8 @@ void DocumentSourceBucketAuto::addDocumentToBucket(const pair<Value, Document>&
bucket._max = entry.first;
const size_t numAccumulators = _accumulatorFactories.size();
- pExpCtx->variables.setRoot(entry.second);
for (size_t k = 0; k < numAccumulators; k++) {
- bucket._accums[k]->process(_expressions[k]->evaluate(), false);
+ bucket._accums[k]->process(_expressions[k]->evaluate(entry.second), false);
}
}
diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
index d0c338c0855..88b5c4efc46 100644
--- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp
+++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
@@ -325,10 +325,7 @@ void DocumentSourceGraphLookUp::performSearch() {
// Make sure _input is set before calling performSearch().
invariant(_input);
- auto& variables = pExpCtx->variables;
- variables.setRoot(*_input);
- Value startingValue = _startWith->evaluateInternal();
- variables.clearRoot();
+ Value startingValue = _startWith->evaluate(*_input);
// 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 c252d61e102..8f13136f4fe 100644
--- a/src/mongo/db/pipeline/document_source_group.cpp
+++ b/src/mongo/db/pipeline/document_source_group.cpp
@@ -128,27 +128,22 @@ DocumentSource::GetNextResult DocumentSourceGroup::getNextStandard() {
DocumentSource::GetNextResult DocumentSourceGroup::getNextStreaming() {
// Streaming optimization is active.
- auto& variables = pExpCtx->variables;
if (!_firstDocOfNextGroup) {
auto nextInput = pSource->getNext();
if (!nextInput.isAdvanced()) {
return nextInput;
}
_firstDocOfNextGroup = nextInput.releaseDocument();
- variables.setRoot(*_firstDocOfNextGroup);
}
Value id;
do {
// Add to the current accumulator(s).
for (size_t i = 0; i < _currentAccumulators.size(); i++) {
- _currentAccumulators[i]->process(vpExpression[i]->evaluate(), _doingMerge);
+ _currentAccumulators[i]->process(vpExpression[i]->evaluate(*_firstDocOfNextGroup),
+ _doingMerge);
}
- // Release our references to the previous input document before asking for the next. This
- // makes operations like $unwind more efficient.
- variables.clearRoot();
-
// Retrieve the next document.
auto nextInput = pSource->getNext();
if (!nextInput.isAdvanced()) {
@@ -157,11 +152,10 @@ DocumentSource::GetNextResult DocumentSourceGroup::getNextStreaming() {
_firstDocOfNextGroup = nextInput.releaseDocument();
- variables.setRoot(*_firstDocOfNextGroup);
// Compute the id. If it does not match _currentId, we will exit the loop, leaving
// _firstDocOfNextGroup set for the next time getNext() is called.
- id = computeId();
+ id = computeId(*_firstDocOfNextGroup);
} while (pExpCtx->getValueComparator().evaluate(_currentId == id));
Document out = makeDocument(_currentId, _currentAccumulators, pExpCtx->inShard);
@@ -479,10 +473,9 @@ DocumentSource::GetNextResult DocumentSourceGroup::initialize() {
return firstInput;
}
_firstDocOfNextGroup = firstInput.releaseDocument();
- pExpCtx->variables.setRoot(*_firstDocOfNextGroup);
// Compute the _id value.
- _currentId = computeId();
+ _currentId = computeId(*_firstDocOfNextGroup);
_initialized = true;
return DocumentSource::GetNextResult::makeEOF();
}
@@ -501,10 +494,7 @@ DocumentSource::GetNextResult DocumentSourceGroup::initialize() {
_memoryUsageBytes = 0;
}
- auto& variables = pExpCtx->variables;
- variables.setRoot(input.releaseDocument());
-
- Value id = computeId();
+ Value id = computeId(input.getDocument());
// Look for the _id value in the map. If it's not there, add a new entry with a blank
// accumulator. This is done in a somewhat odd way in order to avoid hashing 'id' and
@@ -532,13 +522,10 @@ DocumentSource::GetNextResult DocumentSourceGroup::initialize() {
dassert(numAccumulators == group.size());
for (size_t i = 0; i < numAccumulators; i++) {
- group[i]->process(vpExpression[i]->evaluate(), _doingMerge);
+ group[i]->process(vpExpression[i]->evaluate(input.getDocument()), _doingMerge);
_memoryUsageBytes += group[i]->memUsageForSorter();
}
- // We are done with the ROOT document so release it.
- variables.clearRoot();
-
if (kDebugBuild && !storageGlobalParams.readOnly) {
// In debug mode, spill every time we have a duplicate id to stress merge logic.
if (!inserted && // is a dup
@@ -782,10 +769,10 @@ BSONObjSet DocumentSourceGroup::getOutputSorts() {
}
-Value DocumentSourceGroup::computeId() {
+Value DocumentSourceGroup::computeId(Document root) {
// If only one expression, return result directly
if (_idExpressions.size() == 1) {
- Value retValue = _idExpressions[0]->evaluate();
+ Value retValue = _idExpressions[0]->evaluate(root);
return retValue.missing() ? Value(BSONNULL) : std::move(retValue);
}
@@ -793,7 +780,7 @@ Value DocumentSourceGroup::computeId() {
vector<Value> vals;
vals.reserve(_idExpressions.size());
for (size_t i = 0; i < _idExpressions.size(); i++) {
- vals.push_back(_idExpressions[i]->evaluate());
+ vals.push_back(_idExpressions[i]->evaluate(root));
}
return Value(std::move(vals));
}
diff --git a/src/mongo/db/pipeline/document_source_group.h b/src/mongo/db/pipeline/document_source_group.h
index 474952a3203..9fdcd40b373 100644
--- a/src/mongo/db/pipeline/document_source_group.h
+++ b/src/mongo/db/pipeline/document_source_group.h
@@ -140,7 +140,7 @@ private:
/**
* Computes the internal representation of the group key.
*/
- Value computeId();
+ Value computeId(Document root);
/**
* Converts the internal representation of the group key to the _id shape specified by the
diff --git a/src/mongo/db/pipeline/document_source_redact.cpp b/src/mongo/db/pipeline/document_source_redact.cpp
index 738a55cc056..30561034aa0 100644
--- a/src/mongo/db/pipeline/document_source_redact.cpp
+++ b/src/mongo/db/pipeline/document_source_redact.cpp
@@ -64,9 +64,8 @@ DocumentSource::GetNextResult DocumentSourceRedact::getNext() {
auto nextInput = pSource->getNext();
for (; nextInput.isAdvanced(); nextInput = pSource->getNext()) {
auto& variables = pExpCtx->variables;
- variables.setRoot(nextInput.getDocument());
- variables.setValue(_currentId, Value(nextInput.releaseDocument()));
- if (boost::optional<Document> result = redactObject()) {
+ variables.setValue(_currentId, Value(nextInput.getDocument()));
+ if (boost::optional<Document> result = redactObject(nextInput.releaseDocument())) {
return std::move(*result);
}
}
@@ -97,11 +96,11 @@ Pipeline::SourceContainer::iterator DocumentSourceRedact::doOptimizeAt(
return std::next(itr);
}
-Value DocumentSourceRedact::redactValue(const Value& in) {
+Value DocumentSourceRedact::redactValue(const Value& in, Document root) {
const BSONType valueType = in.getType();
if (valueType == Object) {
pExpCtx->variables.setValue(_currentId, in);
- const boost::optional<Document> result = redactObject();
+ const boost::optional<Document> result = redactObject(root);
if (result) {
return Value(*result);
} else {
@@ -113,7 +112,7 @@ Value DocumentSourceRedact::redactValue(const Value& in) {
const vector<Value>& arr = in.getArray();
for (size_t i = 0; i < arr.size(); i++) {
if (arr[i].getType() == Object || arr[i].getType() == Array) {
- const Value toAdd = redactValue(arr[i]);
+ const Value toAdd = redactValue(arr[i], root);
if (!toAdd.missing()) {
newArr.push_back(toAdd);
}
@@ -127,17 +126,17 @@ Value DocumentSourceRedact::redactValue(const Value& in) {
}
}
-boost::optional<Document> DocumentSourceRedact::redactObject() {
+boost::optional<Document> DocumentSourceRedact::redactObject(Document root) {
auto& variables = pExpCtx->variables;
- const Value expressionResult = _expression->evaluate();
+ const Value expressionResult = _expression->evaluate(root);
ValueComparator simpleValueCmp;
if (simpleValueCmp.evaluate(expressionResult == keepVal)) {
- return variables.getDocument(_currentId);
+ return variables.getDocument(_currentId, root);
} else if (simpleValueCmp.evaluate(expressionResult == pruneVal)) {
return boost::optional<Document>();
} else if (simpleValueCmp.evaluate(expressionResult == descendVal)) {
- const Document in = variables.getDocument(_currentId);
+ const Document in = variables.getDocument(_currentId, root);
MutableDocument out;
out.copyMetaDataFrom(in);
FieldIterator fields(in);
@@ -145,7 +144,7 @@ boost::optional<Document> DocumentSourceRedact::redactObject() {
const Document::FieldPair field(fields.next());
// This changes CURRENT so don't read from variables after this
- const Value val = redactValue(field.second);
+ const Value val = redactValue(field.second, root);
if (!val.missing()) {
out.addField(field.first, val);
}
diff --git a/src/mongo/db/pipeline/document_source_redact.h b/src/mongo/db/pipeline/document_source_redact.h
index b894ec9e3f2..82d8666ebaf 100644
--- a/src/mongo/db/pipeline/document_source_redact.h
+++ b/src/mongo/db/pipeline/document_source_redact.h
@@ -57,8 +57,8 @@ private:
const boost::intrusive_ptr<Expression>& previsit);
// These both work over pExpCtx->variables.
- boost::optional<Document> redactObject(); // redacts CURRENT
- Value redactValue(const Value& in);
+ boost::optional<Document> redactObject(Document root); // redacts CURRENT
+ Value redactValue(const Value& in, Document root);
Variables::Id _currentId;
boost::intrusive_ptr<Expression> _expression;
diff --git a/src/mongo/db/pipeline/document_source_replace_root.cpp b/src/mongo/db/pipeline/document_source_replace_root.cpp
index d089e67d097..5e2c15792c0 100644
--- a/src/mongo/db/pipeline/document_source_replace_root.cpp
+++ b/src/mongo/db/pipeline/document_source_replace_root.cpp
@@ -54,8 +54,7 @@ public:
Document applyTransformation(Document input) final {
// Extract subdocument in the form of a Value.
- _expCtx->variables.setRoot(input);
- Value newRoot = _newRoot->evaluate();
+ Value newRoot = _newRoot->evaluate(input);
// 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 e757edde217..b0cb3e989e9 100644
--- a/src/mongo/db/pipeline/document_source_sort.cpp
+++ b/src/mongo/db/pipeline/document_source_sort.cpp
@@ -306,15 +306,14 @@ void DocumentSourceSort::populateFromCursors(const vector<DBClientCursor*>& curs
}
Value DocumentSourceSort::extractKey(const Document& d) const {
- pExpCtx->variables.setRoot(d);
if (vSortKey.size() == 1) {
- return vSortKey[0]->evaluate();
+ return vSortKey[0]->evaluate(d);
}
vector<Value> keys;
keys.reserve(vSortKey.size());
for (size_t i = 0; i < vSortKey.size(); i++) {
- keys.push_back(vSortKey[i]->evaluate());
+ keys.push_back(vSortKey[i]->evaluate(d));
}
return Value(std::move(keys));
}
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 17156acae47..3f6667e217c 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -231,7 +231,7 @@ const char* ExpressionAbs::getOpName() const {
/* ------------------------- ExpressionAdd ----------------------------- */
-Value ExpressionAdd::evaluateInternal() const {
+Value ExpressionAdd::evaluate(Document root) 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
@@ -243,7 +243,7 @@ Value ExpressionAdd::evaluateInternal() const {
const size_t n = vpOperand.size();
for (size_t i = 0; i < n; ++i) {
- Value val = vpOperand[i]->evaluateInternal();
+ Value val = vpOperand[i]->evaluate(root);
switch (val.getType()) {
case NumberDecimal:
@@ -313,8 +313,8 @@ const char* ExpressionAdd::getOpName() const {
/* ------------------------- ExpressionAllElementsTrue -------------------------- */
-Value ExpressionAllElementsTrue::evaluateInternal() const {
- const Value arr = vpOperand[0]->evaluateInternal();
+Value ExpressionAllElementsTrue::evaluate(Document root) const {
+ const Value arr = vpOperand[0]->evaluate(root);
uassert(17040,
str::stream() << getOpName() << "'s argument must be an array, but is "
<< typeName(arr.getType()),
@@ -391,10 +391,10 @@ intrusive_ptr<Expression> ExpressionAnd::optimize() {
return pE;
}
-Value ExpressionAnd::evaluateInternal() const {
+Value ExpressionAnd::evaluate(Document root) const {
const size_t n = vpOperand.size();
for (size_t i = 0; i < n; ++i) {
- Value pValue(vpOperand[i]->evaluateInternal());
+ Value pValue(vpOperand[i]->evaluate(root));
if (!pValue.coerceToBool())
return Value(false);
}
@@ -409,8 +409,8 @@ const char* ExpressionAnd::getOpName() const {
/* ------------------------- ExpressionAnyElementTrue -------------------------- */
-Value ExpressionAnyElementTrue::evaluateInternal() const {
- const Value arr = vpOperand[0]->evaluateInternal();
+Value ExpressionAnyElementTrue::evaluate(Document root) const {
+ const Value arr = vpOperand[0]->evaluate(root);
uassert(17041,
str::stream() << getOpName() << "'s argument must be an array, but is "
<< typeName(arr.getType()),
@@ -431,11 +431,11 @@ const char* ExpressionAnyElementTrue::getOpName() const {
/* ---------------------- ExpressionArray --------------------------- */
-Value ExpressionArray::evaluateInternal() const {
+Value ExpressionArray::evaluate(Document root) const {
vector<Value> values;
values.reserve(vpOperand.size());
for (auto&& expr : vpOperand) {
- Value elemVal = expr->evaluateInternal();
+ Value elemVal = expr->evaluate(root);
values.push_back(elemVal.missing() ? Value(BSONNULL) : std::move(elemVal));
}
return Value(std::move(values));
@@ -457,9 +457,9 @@ const char* ExpressionArray::getOpName() const {
/* ------------------------- ExpressionArrayElemAt -------------------------- */
-Value ExpressionArrayElemAt::evaluateInternal() const {
- const Value array = vpOperand[0]->evaluateInternal();
- const Value indexArg = vpOperand[1]->evaluateInternal();
+Value ExpressionArrayElemAt::evaluate(Document root) const {
+ const Value array = vpOperand[0]->evaluate(root);
+ const Value indexArg = vpOperand[1]->evaluate(root);
if (array.nullish() || indexArg.nullish()) {
return Value(BSONNULL);
@@ -499,8 +499,8 @@ const char* ExpressionArrayElemAt::getOpName() const {
/* ------------------------- ExpressionObjectToArray -------------------------- */
-Value ExpressionObjectToArray::evaluateInternal() const {
- const Value targetVal = vpOperand[0]->evaluateInternal();
+Value ExpressionObjectToArray::evaluate(Document root) const {
+ const Value targetVal = vpOperand[0]->evaluate(root);
if (targetVal.nullish()) {
return Value(BSONNULL);
@@ -531,8 +531,8 @@ const char* ExpressionObjectToArray::getOpName() const {
}
/* ------------------------- ExpressionArrayToObject -------------------------- */
-Value ExpressionArrayToObject::evaluateInternal() const {
- const Value input = vpOperand[0]->evaluateInternal();
+Value ExpressionArrayToObject::evaluate(Document root) const {
+ const Value input = vpOperand[0]->evaluate(root);
if (input.nullish()) {
return Value(BSONNULL);
}
@@ -680,8 +680,8 @@ void ExpressionCoerceToBool::addDependencies(DepsTracker* deps) const {
pExpression->addDependencies(deps);
}
-Value ExpressionCoerceToBool::evaluateInternal() const {
- Value pResult(pExpression->evaluateInternal());
+Value ExpressionCoerceToBool::evaluate(Document root) const {
+ Value pResult(pExpression->evaluate(root));
bool b = pResult.coerceToBool();
if (b)
return Value(true);
@@ -782,9 +782,9 @@ static const CmpLookup cmpLookup[7] = {
};
}
-Value ExpressionCompare::evaluateInternal() const {
- Value pLeft(vpOperand[0]->evaluateInternal());
- Value pRight(vpOperand[1]->evaluateInternal());
+Value ExpressionCompare::evaluate(Document root) const {
+ Value pLeft(vpOperand[0]->evaluate(root));
+ Value pRight(vpOperand[1]->evaluate(root));
int cmp = getExpressionContext()->getValueComparator().compare(pLeft, pRight);
@@ -810,12 +810,12 @@ const char* ExpressionCompare::getOpName() const {
/* ------------------------- ExpressionConcat ----------------------------- */
-Value ExpressionConcat::evaluateInternal() const {
+Value ExpressionConcat::evaluate(Document root) const {
const size_t n = vpOperand.size();
StringBuilder result;
for (size_t i = 0; i < n; ++i) {
- Value val = vpOperand[i]->evaluateInternal();
+ Value val = vpOperand[i]->evaluate(root);
if (val.nullish())
return Value(BSONNULL);
@@ -836,12 +836,12 @@ const char* ExpressionConcat::getOpName() const {
/* ------------------------- ExpressionConcatArrays ----------------------------- */
-Value ExpressionConcatArrays::evaluateInternal() const {
+Value ExpressionConcatArrays::evaluate(Document root) const {
const size_t n = vpOperand.size();
vector<Value> values;
for (size_t i = 0; i < n; ++i) {
- Value val = vpOperand[i]->evaluateInternal();
+ Value val = vpOperand[i]->evaluate(root);
if (val.nullish()) {
return Value(BSONNULL);
}
@@ -864,10 +864,10 @@ const char* ExpressionConcatArrays::getOpName() const {
/* ----------------------- ExpressionCond ------------------------------ */
-Value ExpressionCond::evaluateInternal() const {
- Value pCond(vpOperand[0]->evaluateInternal());
+Value ExpressionCond::evaluate(Document root) const {
+ Value pCond(vpOperand[0]->evaluate(root));
int idx = pCond.coerceToBool() ? 1 : 2;
- return vpOperand[idx]->evaluateInternal();
+ return vpOperand[idx]->evaluate(root);
}
intrusive_ptr<Expression> ExpressionCond::parse(
@@ -938,7 +938,7 @@ void ExpressionConstant::addDependencies(DepsTracker* deps) const {
/* nothing to do */
}
-Value ExpressionConstant::evaluateInternal() const {
+Value ExpressionConstant::evaluate(Document root) const {
return pValue;
}
@@ -1008,8 +1008,8 @@ Value ExpressionDateToString::serialize(bool explain) const {
DOC("$dateToString" << DOC("format" << _format << "date" << _date->serialize(explain))));
}
-Value ExpressionDateToString::evaluateInternal() const {
- const Value date = _date->evaluateInternal();
+Value ExpressionDateToString::evaluate(Document root) const {
+ const Value date = _date->evaluate(root);
if (date.nullish()) {
return Value(BSONNULL);
@@ -1158,8 +1158,8 @@ void ExpressionDateToString::addDependencies(DepsTracker* deps) const {
/* ---------------------- ExpressionDayOfMonth ------------------------- */
-Value ExpressionDayOfMonth::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionDayOfMonth::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -1170,8 +1170,8 @@ const char* ExpressionDayOfMonth::getOpName() const {
/* ------------------------- ExpressionDayOfWeek ----------------------------- */
-Value ExpressionDayOfWeek::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionDayOfWeek::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -1182,8 +1182,8 @@ const char* ExpressionDayOfWeek::getOpName() const {
/* ------------------------- ExpressionDayOfYear ----------------------------- */
-Value ExpressionDayOfYear::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionDayOfYear::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -1194,9 +1194,9 @@ const char* ExpressionDayOfYear::getOpName() const {
/* ----------------------- ExpressionDivide ---------------------------- */
-Value ExpressionDivide::evaluateInternal() const {
- Value lhs = vpOperand[0]->evaluateInternal();
- Value rhs = vpOperand[1]->evaluateInternal();
+Value ExpressionDivide::evaluate(Document root) const {
+ Value lhs = vpOperand[0]->evaluate(root);
+ Value rhs = vpOperand[1]->evaluate(root);
auto assertNonZero = [](bool nonZero) { uassert(16608, "can't $divide by zero", nonZero); };
@@ -1295,10 +1295,10 @@ void ExpressionObject::addDependencies(DepsTracker* deps) const {
}
}
-Value ExpressionObject::evaluateInternal() const {
+Value ExpressionObject::evaluate(Document root) const {
MutableDocument outputDoc;
for (auto&& pair : _expressions) {
- outputDoc.addField(pair.first, pair.second->evaluateInternal());
+ outputDoc.addField(pair.first, pair.second->evaluate(root));
}
return outputDoc.freezeToValue();
}
@@ -1408,17 +1408,17 @@ Value ExpressionFieldPath::evaluatePath(size_t index, const Document& input) con
}
}
-Value ExpressionFieldPath::evaluateInternal() const {
+Value ExpressionFieldPath::evaluate(Document root) const {
auto& vars = getExpressionContext()->variables;
if (_fieldPath.getPathLength() == 1) // get the whole variable
- return vars.getValue(_variable);
+ return vars.getValue(_variable, root);
if (_variable == Variables::kRootId) {
// ROOT is always a document so use optimized code path
- return evaluatePath(1, vars.getRoot());
+ return evaluatePath(1, root);
}
- Value var = vars.getValue(_variable);
+ Value var = vars.getValue(_variable, root);
switch (var.getType()) {
case Object:
return evaluatePath(1, var.getDocument());
@@ -1512,9 +1512,9 @@ Value ExpressionFilter::serialize(bool explain) const {
<< _filter->serialize(explain))));
}
-Value ExpressionFilter::evaluateInternal() const {
+Value ExpressionFilter::evaluate(Document root) const {
// We are guaranteed at parse time that this isn't using our _varId.
- const Value inputVal = _input->evaluateInternal();
+ const Value inputVal = _input->evaluate(root);
if (inputVal.nullish())
return Value(BSONNULL);
@@ -1533,7 +1533,7 @@ Value ExpressionFilter::evaluateInternal() const {
for (const auto& elem : input) {
vars.setValue(_varId, elem);
- if (_filter->evaluateInternal().coerceToBool()) {
+ if (_filter->evaluate(root).coerceToBool()) {
output.push_back(std::move(elem));
}
}
@@ -1646,15 +1646,15 @@ Value ExpressionLet::serialize(bool explain) const {
DOC("$let" << DOC("vars" << vars.freeze() << "in" << _subExpression->serialize(explain))));
}
-Value ExpressionLet::evaluateInternal() const {
+Value ExpressionLet::evaluate(Document root) 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->evaluateInternal());
+ item.second.expression->evaluate(root));
}
- return _subExpression->evaluateInternal();
+ return _subExpression->evaluate(root);
}
void ExpressionLet::addDependencies(DepsTracker* deps) const {
@@ -1739,9 +1739,9 @@ Value ExpressionMap::serialize(bool explain) const {
<< _each->serialize(explain))));
}
-Value ExpressionMap::evaluateInternal() const {
+Value ExpressionMap::evaluate(Document root) const {
// guaranteed at parse time that this isn't using our _varId
- const Value inputVal = _input->evaluateInternal();
+ const Value inputVal = _input->evaluate(root);
if (inputVal.nullish())
return Value(BSONNULL);
@@ -1759,7 +1759,7 @@ Value ExpressionMap::evaluateInternal() const {
for (size_t i = 0; i < input.size(); i++) {
getExpressionContext()->variables.setValue(_varId, input[i]);
- Value toInsert = _each->evaluateInternal();
+ Value toInsert = _each->evaluate(root);
if (toInsert.missing())
toInsert = Value(BSONNULL); // can't insert missing values into array
@@ -1807,8 +1807,7 @@ Value ExpressionMeta::serialize(bool explain) const {
MONGO_UNREACHABLE;
}
-Value ExpressionMeta::evaluateInternal() const {
- const Document& root = getExpressionContext()->variables.getRoot();
+Value ExpressionMeta::evaluate(Document root) const {
switch (_metaType) {
case MetaType::TEXT_SCORE:
return root.hasTextScore() ? Value(root.getTextScore()) : Value();
@@ -1826,8 +1825,8 @@ void ExpressionMeta::addDependencies(DepsTracker* deps) const {
/* ------------------------- ExpressionMillisecond ----------------------------- */
-Value ExpressionMillisecond::evaluateInternal() const {
- Value date(vpOperand[0]->evaluateInternal());
+Value ExpressionMillisecond::evaluate(Document root) const {
+ Value date(vpOperand[0]->evaluate(root));
return Value(extract(date.coerceToDate()));
}
@@ -1844,8 +1843,8 @@ const char* ExpressionMillisecond::getOpName() const {
/* ------------------------- ExpressionMinute -------------------------- */
-Value ExpressionMinute::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionMinute::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -1856,9 +1855,9 @@ const char* ExpressionMinute::getOpName() const {
/* ----------------------- ExpressionMod ---------------------------- */
-Value ExpressionMod::evaluateInternal() const {
- Value lhs = vpOperand[0]->evaluateInternal();
- Value rhs = vpOperand[1]->evaluateInternal();
+Value ExpressionMod::evaluate(Document root) const {
+ Value lhs = vpOperand[0]->evaluate(root);
+ Value rhs = vpOperand[1]->evaluate(root);
BSONType leftType = lhs.getType();
BSONType rightType = rhs.getType();
@@ -1913,8 +1912,8 @@ const char* ExpressionMod::getOpName() const {
/* ------------------------ ExpressionMonth ----------------------------- */
-Value ExpressionMonth::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionMonth::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -1925,7 +1924,7 @@ const char* ExpressionMonth::getOpName() const {
/* ------------------------- ExpressionMultiply ----------------------------- */
-Value ExpressionMultiply::evaluateInternal() const {
+Value ExpressionMultiply::evaluate(Document root) const {
/*
We'll try to return the narrowest possible result value. To do that
without creating intermediate Values, do the arithmetic for double
@@ -1940,7 +1939,7 @@ Value ExpressionMultiply::evaluateInternal() const {
const size_t n = vpOperand.size();
for (size_t i = 0; i < n; ++i) {
- Value val = vpOperand[i]->evaluateInternal();
+ Value val = vpOperand[i]->evaluate(root);
if (val.numeric()) {
BSONType oldProductType = productType;
@@ -1988,8 +1987,8 @@ const char* ExpressionMultiply::getOpName() const {
/* ------------------------- ExpressionHour ----------------------------- */
-Value ExpressionHour::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionHour::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -2000,12 +1999,12 @@ const char* ExpressionHour::getOpName() const {
/* ----------------------- ExpressionIfNull ---------------------------- */
-Value ExpressionIfNull::evaluateInternal() const {
- Value pLeft(vpOperand[0]->evaluateInternal());
+Value ExpressionIfNull::evaluate(Document root) const {
+ Value pLeft(vpOperand[0]->evaluate(root));
if (!pLeft.nullish())
return pLeft;
- Value pRight(vpOperand[1]->evaluateInternal());
+ Value pRight(vpOperand[1]->evaluate(root));
return pRight;
}
@@ -2016,9 +2015,9 @@ const char* ExpressionIfNull::getOpName() const {
/* ----------------------- ExpressionIn ---------------------------- */
-Value ExpressionIn::evaluateInternal() const {
- Value argument(vpOperand[0]->evaluateInternal());
- Value arrayOfValues(vpOperand[1]->evaluateInternal());
+Value ExpressionIn::evaluate(Document root) const {
+ Value argument(vpOperand[0]->evaluate(root));
+ Value arrayOfValues(vpOperand[1]->evaluate(root));
uassert(40081,
str::stream() << "$in requires an array as a second argument, found: "
@@ -2060,8 +2059,8 @@ void uassertIfNotIntegralAndNonNegative(Value val,
} // namespace
-Value ExpressionIndexOfArray::evaluateInternal() const {
- Value arrayArg = vpOperand[0]->evaluateInternal();
+Value ExpressionIndexOfArray::evaluate(Document root) const {
+ Value arrayArg = vpOperand[0]->evaluate(root);
if (arrayArg.nullish()) {
return Value(BSONNULL);
@@ -2074,18 +2073,18 @@ Value ExpressionIndexOfArray::evaluateInternal() const {
std::vector<Value> array = arrayArg.getArray();
- Value searchItem = vpOperand[1]->evaluateInternal();
+ Value searchItem = vpOperand[1]->evaluate(root);
size_t startIndex = 0;
if (vpOperand.size() > 2) {
- Value startIndexArg = vpOperand[2]->evaluateInternal();
+ Value startIndexArg = vpOperand[2]->evaluate(root);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startIndex = static_cast<size_t>(startIndexArg.coerceToInt());
}
size_t endIndex = array.size();
if (vpOperand.size() > 3) {
- Value endIndexArg = vpOperand[3]->evaluateInternal();
+ Value endIndexArg = vpOperand[3]->evaluate(root);
uassertIfNotIntegralAndNonNegative(endIndexArg, getOpName(), "ending index");
// Don't let 'endIndex' exceed the length of the array.
endIndex = std::min(array.size(), static_cast<size_t>(endIndexArg.coerceToInt()));
@@ -2118,8 +2117,8 @@ bool stringHasTokenAtIndex(size_t index, const std::string& input, const std::st
} // namespace
-Value ExpressionIndexOfBytes::evaluateInternal() const {
- Value stringArg = vpOperand[0]->evaluateInternal();
+Value ExpressionIndexOfBytes::evaluate(Document root) const {
+ Value stringArg = vpOperand[0]->evaluate(root);
if (stringArg.nullish()) {
return Value(BSONNULL);
@@ -2131,7 +2130,7 @@ Value ExpressionIndexOfBytes::evaluateInternal() const {
stringArg.getType() == String);
const std::string& input = stringArg.getString();
- Value tokenArg = vpOperand[1]->evaluateInternal();
+ Value tokenArg = vpOperand[1]->evaluate(root);
uassert(40092,
str::stream() << "$indexOfBytes requires a string as the second argument, found: "
<< typeName(tokenArg.getType()),
@@ -2140,14 +2139,14 @@ Value ExpressionIndexOfBytes::evaluateInternal() const {
size_t startIndex = 0;
if (vpOperand.size() > 2) {
- Value startIndexArg = vpOperand[2]->evaluateInternal();
+ Value startIndexArg = vpOperand[2]->evaluate(root);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startIndex = static_cast<size_t>(startIndexArg.coerceToInt());
}
size_t endIndex = input.size();
if (vpOperand.size() > 3) {
- Value endIndexArg = vpOperand[3]->evaluateInternal();
+ Value endIndexArg = vpOperand[3]->evaluate(root);
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()));
@@ -2172,8 +2171,8 @@ const char* ExpressionIndexOfBytes::getOpName() const {
/* ----------------------- ExpressionIndexOfCP --------------------- */
-Value ExpressionIndexOfCP::evaluateInternal() const {
- Value stringArg = vpOperand[0]->evaluateInternal();
+Value ExpressionIndexOfCP::evaluate(Document root) const {
+ Value stringArg = vpOperand[0]->evaluate(root);
if (stringArg.nullish()) {
return Value(BSONNULL);
@@ -2185,7 +2184,7 @@ Value ExpressionIndexOfCP::evaluateInternal() const {
stringArg.getType() == String);
const std::string& input = stringArg.getString();
- Value tokenArg = vpOperand[1]->evaluateInternal();
+ Value tokenArg = vpOperand[1]->evaluate(root);
uassert(40094,
str::stream() << "$indexOfCP requires a string as the second argument, found: "
<< typeName(tokenArg.getType()),
@@ -2194,7 +2193,7 @@ Value ExpressionIndexOfCP::evaluateInternal() const {
size_t startCodePointIndex = 0;
if (vpOperand.size() > 2) {
- Value startIndexArg = vpOperand[2]->evaluateInternal();
+ Value startIndexArg = vpOperand[2]->evaluate(root);
uassertIfNotIntegralAndNonNegative(startIndexArg, getOpName(), "starting index");
startCodePointIndex = static_cast<size_t>(startIndexArg.coerceToInt());
}
@@ -2216,7 +2215,7 @@ Value ExpressionIndexOfCP::evaluateInternal() const {
size_t endCodePointIndex = codePointLength;
if (vpOperand.size() > 3) {
- Value endIndexArg = vpOperand[3]->evaluateInternal();
+ Value endIndexArg = vpOperand[3]->evaluate(root);
uassertIfNotIntegralAndNonNegative(endIndexArg, getOpName(), "ending index");
// Don't let 'endCodePointIndex' exceed the number of code points in the string.
@@ -2273,9 +2272,9 @@ const char* ExpressionLn::getOpName() const {
/* ----------------------- ExpressionLog ---------------------------- */
-Value ExpressionLog::evaluateInternal() const {
- Value argVal = vpOperand[0]->evaluateInternal();
- Value baseVal = vpOperand[1]->evaluateInternal();
+Value ExpressionLog::evaluate(Document root) const {
+ Value argVal = vpOperand[0]->evaluate(root);
+ Value baseVal = vpOperand[1]->evaluate(root);
if (argVal.nullish() || baseVal.nullish())
return Value(BSONNULL);
@@ -2368,7 +2367,7 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
// expression.
if (constOperandCount == vpOperand.size()) {
return intrusive_ptr<Expression>(
- ExpressionConstant::create(getExpressionContext(), evaluateInternal()));
+ ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
}
// If the expression is associative, we can collapse all the consecutive constant operands into
@@ -2412,7 +2411,7 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
ExpressionVector vpOperandSave = std::move(vpOperand);
vpOperand = std::move(constExpressions);
optimizedOperands.emplace_back(
- ExpressionConstant::create(getExpressionContext(), evaluateInternal()));
+ ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
vpOperand = std::move(vpOperandSave);
} else {
optimizedOperands.insert(
@@ -2427,7 +2426,7 @@ intrusive_ptr<Expression> ExpressionNary::optimize() {
if (constExpressions.size() > 1) {
vpOperand = std::move(constExpressions);
optimizedOperands.emplace_back(
- ExpressionConstant::create(getExpressionContext(), evaluateInternal()));
+ ExpressionConstant::create(getExpressionContext(), evaluate(Document())));
} else {
optimizedOperands.insert(
optimizedOperands.end(), constExpressions.begin(), constExpressions.end());
@@ -2460,8 +2459,8 @@ Value ExpressionNary::serialize(bool explain) const {
/* ------------------------- ExpressionNot ----------------------------- */
-Value ExpressionNot::evaluateInternal() const {
- Value pOp(vpOperand[0]->evaluateInternal());
+Value ExpressionNot::evaluate(Document root) const {
+ Value pOp(vpOperand[0]->evaluate(root));
bool b = pOp.coerceToBool();
return Value(!b);
@@ -2474,10 +2473,10 @@ const char* ExpressionNot::getOpName() const {
/* -------------------------- ExpressionOr ----------------------------- */
-Value ExpressionOr::evaluateInternal() const {
+Value ExpressionOr::evaluate(Document root) const {
const size_t n = vpOperand.size();
for (size_t i = 0; i < n; ++i) {
- Value pValue(vpOperand[i]->evaluateInternal());
+ Value pValue(vpOperand[i]->evaluate(root));
if (pValue.coerceToBool())
return Value(true);
}
@@ -2554,9 +2553,9 @@ intrusive_ptr<Expression> ExpressionPow::create(
return expr;
}
-Value ExpressionPow::evaluateInternal() const {
- Value baseVal = vpOperand[0]->evaluateInternal();
- Value expVal = vpOperand[1]->evaluateInternal();
+Value ExpressionPow::evaluate(Document root) const {
+ Value baseVal = vpOperand[0]->evaluate(root);
+ Value expVal = vpOperand[1]->evaluate(root);
if (baseVal.nullish() || expVal.nullish())
return Value(BSONNULL);
@@ -2714,9 +2713,9 @@ const char* ExpressionPow::getOpName() const {
/* ------------------------- ExpressionRange ------------------------------ */
-Value ExpressionRange::evaluateInternal() const {
- Value startVal(vpOperand[0]->evaluateInternal());
- Value endVal(vpOperand[1]->evaluateInternal());
+Value ExpressionRange::evaluate(Document root) const {
+ Value startVal(vpOperand[0]->evaluate(root));
+ Value endVal(vpOperand[1]->evaluate(root));
uassert(34443,
str::stream() << "$range requires a numeric starting value, found value of type: "
@@ -2743,7 +2742,7 @@ Value ExpressionRange::evaluateInternal() const {
int step = 1;
if (vpOperand.size() == 3) {
// A step was specified by the user.
- Value stepVal(vpOperand[2]->evaluateInternal());
+ Value stepVal(vpOperand[2]->evaluate(root));
uassert(34447,
str::stream() << "$range requires a numeric step value, found value of type:"
@@ -2814,8 +2813,8 @@ intrusive_ptr<Expression> ExpressionReduce::parse(
return reduce;
}
-Value ExpressionReduce::evaluateInternal() const {
- Value inputVal = _input->evaluateInternal();
+Value ExpressionReduce::evaluate(Document root) const {
+ Value inputVal = _input->evaluate(root);
if (inputVal.nullish()) {
return Value(BSONNULL);
@@ -2826,14 +2825,14 @@ Value ExpressionReduce::evaluateInternal() const {
<< inputVal.toString(),
inputVal.isArray());
- Value accumulatedValue = _initial->evaluateInternal();
+ Value accumulatedValue = _initial->evaluate(root);
auto& vars = getExpressionContext()->variables;
for (auto&& elem : inputVal.getArray()) {
vars.setValue(_thisVar, elem);
vars.setValue(_valueVar, accumulatedValue);
- accumulatedValue = _in->evaluateInternal();
+ accumulatedValue = _in->evaluate(root);
}
return accumulatedValue;
@@ -2861,8 +2860,8 @@ Value ExpressionReduce::serialize(bool explain) const {
/* ------------------------ ExpressionReverseArray ------------------------ */
-Value ExpressionReverseArray::evaluateInternal() const {
- Value input(vpOperand[0]->evaluateInternal());
+Value ExpressionReverseArray::evaluate(Document root) const {
+ Value input(vpOperand[0]->evaluate(root));
if (input.nullish()) {
return Value(BSONNULL);
@@ -2889,8 +2888,8 @@ const char* ExpressionReverseArray::getOpName() const {
/* ------------------------- ExpressionSecond ----------------------------- */
-Value ExpressionSecond::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionSecond::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -2910,9 +2909,9 @@ ValueSet arrayToSet(const Value& val, const ValueComparator& valueComparator) {
/* ----------------------- ExpressionSetDifference ---------------------------- */
-Value ExpressionSetDifference::evaluateInternal() const {
- const Value lhs = vpOperand[0]->evaluateInternal();
- const Value rhs = vpOperand[1]->evaluateInternal();
+Value ExpressionSetDifference::evaluate(Document root) const {
+ const Value lhs = vpOperand[0]->evaluate(root);
+ const Value rhs = vpOperand[1]->evaluate(root);
if (lhs.nullish() || rhs.nullish()) {
return Value(BSONNULL);
@@ -2956,13 +2955,13 @@ void ExpressionSetEquals::validateArguments(const ExpressionVector& args) const
args.size() >= 2);
}
-Value ExpressionSetEquals::evaluateInternal() const {
+Value ExpressionSetEquals::evaluate(Document root) const {
const size_t n = vpOperand.size();
const auto& valueComparator = getExpressionContext()->getValueComparator();
ValueSet lhs = valueComparator.makeOrderedValueSet();
for (size_t i = 0; i < n; i++) {
- const Value nextEntry = vpOperand[i]->evaluateInternal();
+ const Value nextEntry = vpOperand[i]->evaluate(root);
uassert(17044,
str::stream() << "All operands of $setEquals must be arrays. One "
<< "argument is of type: "
@@ -2993,12 +2992,12 @@ const char* ExpressionSetEquals::getOpName() const {
/* ----------------------- ExpressionSetIntersection ---------------------------- */
-Value ExpressionSetIntersection::evaluateInternal() const {
+Value ExpressionSetIntersection::evaluate(Document root) const {
const size_t n = vpOperand.size();
const auto& valueComparator = getExpressionContext()->getValueComparator();
ValueSet currentIntersection = valueComparator.makeOrderedValueSet();
for (size_t i = 0; i < n; i++) {
- const Value nextEntry = vpOperand[i]->evaluateInternal();
+ const Value nextEntry = vpOperand[i]->evaluate(root);
if (nextEntry.nullish()) {
return Value(BSONNULL);
}
@@ -3054,9 +3053,9 @@ Value setIsSubsetHelper(const vector<Value>& lhs, const ValueSet& rhs) {
}
}
-Value ExpressionSetIsSubset::evaluateInternal() const {
- const Value lhs = vpOperand[0]->evaluateInternal();
- const Value rhs = vpOperand[1]->evaluateInternal();
+Value ExpressionSetIsSubset::evaluate(Document root) const {
+ const Value lhs = vpOperand[0]->evaluate(root);
+ const Value rhs = vpOperand[1]->evaluate(root);
uassert(17046,
str::stream() << "both operands of $setIsSubset must be arrays. First "
@@ -3089,8 +3088,8 @@ public:
vpOperand = operands;
}
- virtual Value evaluateInternal() const {
- const Value lhs = vpOperand[0]->evaluateInternal();
+ virtual Value evaluate(Document root) const {
+ const Value lhs = vpOperand[0]->evaluate(root);
uassert(17310,
str::stream() << "both operands of $setIsSubset must be arrays. First "
@@ -3137,11 +3136,11 @@ const char* ExpressionSetIsSubset::getOpName() const {
/* ----------------------- ExpressionSetUnion ---------------------------- */
-Value ExpressionSetUnion::evaluateInternal() const {
+Value ExpressionSetUnion::evaluate(Document root) const {
ValueSet unionedSet = getExpressionContext()->getValueComparator().makeOrderedValueSet();
const size_t n = vpOperand.size();
for (size_t i = 0; i < n; i++) {
- const Value newEntries = vpOperand[i]->evaluateInternal();
+ const Value newEntries = vpOperand[i]->evaluate(root);
if (newEntries.nullish()) {
return Value(BSONNULL);
}
@@ -3163,8 +3162,8 @@ const char* ExpressionSetUnion::getOpName() const {
/* ----------------------- ExpressionIsArray ---------------------------- */
-Value ExpressionIsArray::evaluateInternal() const {
- Value argument = vpOperand[0]->evaluateInternal();
+Value ExpressionIsArray::evaluate(Document root) const {
+ Value argument = vpOperand[0]->evaluate(root);
return Value(argument.isArray());
}
@@ -3175,12 +3174,12 @@ const char* ExpressionIsArray::getOpName() const {
/* ----------------------- ExpressionSlice ---------------------------- */
-Value ExpressionSlice::evaluateInternal() const {
+Value ExpressionSlice::evaluate(Document root) const {
const size_t n = vpOperand.size();
- Value arrayVal = vpOperand[0]->evaluateInternal();
+ Value arrayVal = vpOperand[0]->evaluate(root);
// Could be either a start index or the length from 0.
- Value arg2 = vpOperand[1]->evaluateInternal();
+ Value arg2 = vpOperand[1]->evaluate(root);
if (arrayVal.nullish() || arg2.nullish()) {
return Value(BSONNULL);
@@ -3231,7 +3230,7 @@ Value ExpressionSlice::evaluateInternal() const {
start = std::min(array.size(), size_t(startInt));
}
- Value countVal = vpOperand[2]->evaluateInternal();
+ Value countVal = vpOperand[2]->evaluate(root);
if (countVal.nullish()) {
return Value(BSONNULL);
@@ -3266,8 +3265,8 @@ const char* ExpressionSlice::getOpName() const {
/* ----------------------- ExpressionSize ---------------------------- */
-Value ExpressionSize::evaluateInternal() const {
- Value array = vpOperand[0]->evaluateInternal();
+Value ExpressionSize::evaluate(Document root) const {
+ Value array = vpOperand[0]->evaluate(root);
uassert(17124,
str::stream() << "The argument to $size must be an array, but was of type: "
@@ -3283,9 +3282,9 @@ const char* ExpressionSize::getOpName() const {
/* ----------------------- ExpressionSplit --------------------------- */
-Value ExpressionSplit::evaluateInternal() const {
- Value inputArg = vpOperand[0]->evaluateInternal();
- Value separatorArg = vpOperand[1]->evaluateInternal();
+Value ExpressionSplit::evaluate(Document root) const {
+ Value inputArg = vpOperand[0]->evaluate(root);
+ Value separatorArg = vpOperand[1]->evaluate(root);
if (inputArg.nullish() || separatorArg.nullish()) {
return Value(BSONNULL);
@@ -3361,9 +3360,9 @@ const char* ExpressionSqrt::getOpName() const {
/* ----------------------- ExpressionStrcasecmp ---------------------------- */
-Value ExpressionStrcasecmp::evaluateInternal() const {
- Value pString1(vpOperand[0]->evaluateInternal());
- Value pString2(vpOperand[1]->evaluateInternal());
+Value ExpressionStrcasecmp::evaluate(Document root) const {
+ Value pString1(vpOperand[0]->evaluate(root));
+ Value pString2(vpOperand[1]->evaluate(root));
/* boost::iequals returns a bool not an int so strings must actually be allocated */
string str1 = boost::to_upper_copy(pString1.coerceToString());
@@ -3385,10 +3384,10 @@ const char* ExpressionStrcasecmp::getOpName() const {
/* ----------------------- ExpressionSubstrBytes ---------------------------- */
-Value ExpressionSubstrBytes::evaluateInternal() const {
- Value pString(vpOperand[0]->evaluateInternal());
- Value pLower(vpOperand[1]->evaluateInternal());
- Value pLength(vpOperand[2]->evaluateInternal());
+Value ExpressionSubstrBytes::evaluate(Document root) const {
+ Value pString(vpOperand[0]->evaluate(root));
+ Value pLower(vpOperand[1]->evaluate(root));
+ Value pLength(vpOperand[2]->evaluate(root));
string str = pString.coerceToString();
uassert(16034,
@@ -3438,10 +3437,10 @@ const char* ExpressionSubstrBytes::getOpName() const {
/* ----------------------- ExpressionSubstrCP ---------------------------- */
-Value ExpressionSubstrCP::evaluateInternal() const {
- Value inputVal(vpOperand[0]->evaluateInternal());
- Value lowerVal(vpOperand[1]->evaluateInternal());
- Value lengthVal(vpOperand[2]->evaluateInternal());
+Value ExpressionSubstrCP::evaluate(Document root) const {
+ Value inputVal(vpOperand[0]->evaluate(root));
+ Value lowerVal(vpOperand[1]->evaluate(root));
+ Value lengthVal(vpOperand[2]->evaluate(root));
std::string str = inputVal.coerceToString();
uassert(34450,
@@ -3513,8 +3512,8 @@ const char* ExpressionSubstrCP::getOpName() const {
/* ----------------------- ExpressionStrLenBytes ------------------------- */
-Value ExpressionStrLenBytes::evaluateInternal() const {
- Value str(vpOperand[0]->evaluateInternal());
+Value ExpressionStrLenBytes::evaluate(Document root) const {
+ Value str(vpOperand[0]->evaluate(root));
uassert(34473,
str::stream() << "$strLenBytes requires a string argument, found: "
@@ -3536,8 +3535,8 @@ const char* ExpressionStrLenBytes::getOpName() const {
/* ----------------------- ExpressionStrLenCP ------------------------- */
-Value ExpressionStrLenCP::evaluateInternal() const {
- Value val(vpOperand[0]->evaluateInternal());
+Value ExpressionStrLenCP::evaluate(Document root) const {
+ Value val(vpOperand[0]->evaluate(root));
uassert(34471,
str::stream() << "$strLenCP requires a string argument, found: "
@@ -3565,9 +3564,9 @@ const char* ExpressionStrLenCP::getOpName() const {
/* ----------------------- ExpressionSubtract ---------------------------- */
-Value ExpressionSubtract::evaluateInternal() const {
- Value lhs = vpOperand[0]->evaluateInternal();
- Value rhs = vpOperand[1]->evaluateInternal();
+Value ExpressionSubtract::evaluate(Document root) const {
+ Value lhs = vpOperand[0]->evaluate(root);
+ Value rhs = vpOperand[1]->evaluate(root);
BSONType diffType = Value::getWidestNumeric(rhs.getType(), lhs.getType());
@@ -3617,12 +3616,12 @@ const char* ExpressionSubtract::getOpName() const {
REGISTER_EXPRESSION(switch, ExpressionSwitch::parse);
-Value ExpressionSwitch::evaluateInternal() const {
+Value ExpressionSwitch::evaluate(Document root) const {
for (auto&& branch : _branches) {
- Value caseExpression(branch.first->evaluateInternal());
+ Value caseExpression(branch.first->evaluate(root));
if (caseExpression.coerceToBool()) {
- return branch.second->evaluateInternal();
+ return branch.second->evaluate(root);
}
}
@@ -3630,7 +3629,7 @@ Value ExpressionSwitch::evaluateInternal() const {
"$switch could not find a matching branch for an input, and no default was specified.",
_default);
- return _default->evaluateInternal();
+ return _default->evaluate(root);
}
boost::intrusive_ptr<Expression> ExpressionSwitch::parse(
@@ -3744,8 +3743,8 @@ Value ExpressionSwitch::serialize(bool explain) const {
/* ------------------------- ExpressionToLower ----------------------------- */
-Value ExpressionToLower::evaluateInternal() const {
- Value pString(vpOperand[0]->evaluateInternal());
+Value ExpressionToLower::evaluate(Document root) const {
+ Value pString(vpOperand[0]->evaluate(root));
string str = pString.coerceToString();
boost::to_lower(str);
return Value(str);
@@ -3758,8 +3757,8 @@ const char* ExpressionToLower::getOpName() const {
/* ------------------------- ExpressionToUpper -------------------------- */
-Value ExpressionToUpper::evaluateInternal() const {
- Value pString(vpOperand[0]->evaluateInternal());
+Value ExpressionToUpper::evaluate(Document root) const {
+ Value pString(vpOperand[0]->evaluate(root));
string str(pString.coerceToString());
boost::to_upper(str);
return Value(str);
@@ -3792,8 +3791,8 @@ const char* ExpressionTrunc::getOpName() const {
/* ------------------------- ExpressionType ----------------------------- */
-Value ExpressionType::evaluateInternal() const {
- Value val(vpOperand[0]->evaluateInternal());
+Value ExpressionType::evaluate(Document root) const {
+ Value val(vpOperand[0]->evaluate(root));
return Value(StringData(typeName(val.getType())));
}
@@ -3804,8 +3803,8 @@ const char* ExpressionType::getOpName() const {
/* ------------------------- ExpressionWeek ----------------------------- */
-Value ExpressionWeek::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionWeek::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -3836,8 +3835,8 @@ const char* ExpressionWeek::getOpName() const {
/* ------------------------- ExpressionIsoDayOfWeek --------------------- */
-Value ExpressionIsoDayOfWeek::evaluateInternal() const {
- Value date(vpOperand[0]->evaluateInternal());
+Value ExpressionIsoDayOfWeek::evaluate(Document root) const {
+ Value date(vpOperand[0]->evaluate(root));
return Value(extract(date.coerceToTm()));
}
@@ -3853,8 +3852,8 @@ const char* ExpressionIsoDayOfWeek::getOpName() const {
/* ------------------------- ExpressionIsoWeekYear ---------------------- */
-Value ExpressionIsoWeekYear::evaluateInternal() const {
- Value date(vpOperand[0]->evaluateInternal());
+Value ExpressionIsoWeekYear::evaluate(Document root) const {
+ Value date(vpOperand[0]->evaluate(root));
return Value(extract(date.coerceToTm()));
}
@@ -3939,8 +3938,8 @@ int lastWeek(int year) {
}
}
-Value ExpressionIsoWeek::evaluateInternal() const {
- Value date(vpOperand[0]->evaluateInternal());
+Value ExpressionIsoWeek::evaluate(Document root) const {
+ Value date(vpOperand[0]->evaluate(root));
return Value(extract(date.coerceToTm()));
}
@@ -3988,8 +3987,8 @@ const char* ExpressionIsoWeek::getOpName() const {
/* ------------------------- ExpressionYear ----------------------------- */
-Value ExpressionYear::evaluateInternal() const {
- Value pDate(vpOperand[0]->evaluateInternal());
+Value ExpressionYear::evaluate(Document root) const {
+ Value pDate(vpOperand[0]->evaluate(root));
return Value(extract(pDate.coerceToTm()));
}
@@ -4053,7 +4052,7 @@ intrusive_ptr<Expression> ExpressionZip::parse(
return std::move(newZip);
}
-Value ExpressionZip::evaluateInternal() const {
+Value ExpressionZip::evaluate(Document root) const {
// Evaluate input values.
vector<vector<Value>> inputValues;
inputValues.reserve(_inputs.size());
@@ -4061,7 +4060,7 @@ Value ExpressionZip::evaluateInternal() const {
size_t minArraySize = 0;
size_t maxArraySize = 0;
for (size_t i = 0; i < _inputs.size(); i++) {
- Value evalExpr = _inputs[i]->evaluateInternal();
+ Value evalExpr = _inputs[i]->evaluate(root);
if (evalExpr.nullish()) {
return Value(BSONNULL);
}
@@ -4090,7 +4089,7 @@ Value ExpressionZip::evaluateInternal() 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]->evaluateInternal();
+ evaluatedDefaults[i] = _defaults[i]->evaluate(root);
}
}
diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h
index 0bb366223a3..d698fd127f7 100644
--- a/src/mongo/db/pipeline/expression.h
+++ b/src/mongo/db/pipeline/expression.h
@@ -104,20 +104,8 @@ public:
/**
* Evaluate expression with respect to the Document given by 'root', and return the result.
- *
- * This method should only be used for testing.
- */
- Value evaluate(const Document& root) const {
- getExpressionContext()->variables.setRoot(root);
- return evaluate();
- }
-
- /**
- * Evaluate expression and return the result.
*/
- Value evaluate() const {
- return evaluateInternal();
- }
+ virtual Value evaluate(Document root) const = 0;
/**
* Parses a BSON Object that could represent an object literal or a functional expression like
@@ -165,14 +153,6 @@ public:
static std::string removeFieldPrefix(const std::string& prefixedField);
/**
- * Evaluate the subclass Expression and return result.
- *
- * Should only be called by subclasses, but can't be protected because they need to call
- * this function on each other.
- */
- virtual Value evaluateInternal() const = 0;
-
- /**
* Registers an Parser so it can be called from parseExpression.
*
* DO NOT call this method directly. Instead, use the REGISTER_EXPRESSION macro defined in this
@@ -320,13 +300,13 @@ public:
explicit ExpressionFromAccumulator(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionFromAccumulator<Accumulator>>(expCtx) {}
- Value evaluateInternal() const final {
+ Value evaluate(Document root) const final {
Accumulator accum(this->getExpressionContext());
const size_t n = this->vpOperand.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->vpOperand[0]->evaluateInternal();
+ Value singleVal = this->vpOperand[0]->evaluate(root);
if (singleVal.getType() == Array) {
for (const Value& val : singleVal.getArray()) {
accum.process(val, false);
@@ -337,7 +317,7 @@ public:
} else {
// If multiple arguments are given, pass all arguments to the accumulator.
for (auto&& argument : this->vpOperand) {
- accum.process(argument->evaluateInternal(), false);
+ accum.process(argument->evaluate(root), false);
}
}
return accum.getValue(false);
@@ -372,8 +352,8 @@ public:
virtual ~ExpressionSingleNumericArg() {}
- Value evaluateInternal() const final {
- Value arg = this->vpOperand[0]->evaluateInternal();
+ Value evaluate(Document root) const final {
+ Value arg = this->vpOperand[0]->evaluate(root);
if (arg.nullish())
return Value(BSONNULL);
@@ -404,7 +384,7 @@ public:
explicit ExpressionAdd(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionAdd>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -422,7 +402,7 @@ public:
explicit ExpressionAllElementsTrue(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionAllElementsTrue, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -433,7 +413,7 @@ public:
: ExpressionVariadic<ExpressionAnd>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -451,7 +431,7 @@ public:
explicit ExpressionAnyElementTrue(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionAnyElementTrue, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -461,7 +441,7 @@ public:
explicit ExpressionArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionArray>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
Value serialize(bool explain) const final;
const char* getOpName() const final;
};
@@ -472,7 +452,7 @@ public:
explicit ExpressionArrayElemAt(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionArrayElemAt, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -481,7 +461,7 @@ public:
explicit ExpressionObjectToArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionObjectToArray, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -490,7 +470,7 @@ public:
explicit ExpressionArrayToObject(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionArrayToObject, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -508,7 +488,7 @@ class ExpressionCoerceToBool final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
Value serialize(bool explain) const final;
static boost::intrusive_ptr<ExpressionCoerceToBool> create(
@@ -542,7 +522,7 @@ public:
ExpressionCompare(const boost::intrusive_ptr<ExpressionContext>& expCtx, CmpOp cmpOp)
: ExpressionFixedArity<ExpressionCompare, 2>(expCtx), cmpOp(cmpOp) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static boost::intrusive_ptr<Expression> parse(
@@ -567,7 +547,7 @@ public:
explicit ExpressionConcat(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionConcat>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -581,7 +561,7 @@ public:
explicit ExpressionConcatArrays(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionConcatArrays>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -594,7 +574,7 @@ class ExpressionCond final : public ExpressionFixedArity<ExpressionCond, 3> {
public:
explicit ExpressionCond(const boost::intrusive_ptr<ExpressionContext>& expCtx) : Base(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static boost::intrusive_ptr<Expression> parse(
@@ -611,7 +591,7 @@ class ExpressionConstant final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
Value serialize(bool explain) const final;
const char* getOpName() const;
@@ -643,7 +623,7 @@ class ExpressionDateToString final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
void addDependencies(DepsTracker* deps) const final;
static boost::intrusive_ptr<Expression> parse(
@@ -674,7 +654,7 @@ public:
explicit ExpressionDayOfMonth(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionDayOfMonth, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static inline int extract(const tm& tm) {
@@ -688,7 +668,7 @@ public:
explicit ExpressionDayOfWeek(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionDayOfWeek, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
// MySQL uses 1-7, tm uses 0-6
@@ -703,7 +683,7 @@ public:
explicit ExpressionDayOfYear(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionDayOfYear, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
// MySQL uses 1-366, tm uses 0-365
@@ -718,7 +698,7 @@ public:
explicit ExpressionDivide(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionDivide, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -737,7 +717,7 @@ class ExpressionFieldPath final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
Value serialize(bool explain) const final;
/*
@@ -776,7 +756,7 @@ private:
Variables::Id variable);
/*
- Internal implementation of evaluateInternal(), used recursively.
+ Internal implementation of evaluate(), used recursively.
The internal implementation doesn't just use a loop because of
the possibility that we need to skip over an array. If the path
@@ -802,7 +782,7 @@ class ExpressionFilter final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
void addDependencies(DepsTracker* deps) const final;
static boost::intrusive_ptr<Expression> parse(
@@ -843,7 +823,7 @@ public:
explicit ExpressionHour(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionHour, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static inline int extract(const tm& tm) {
@@ -857,7 +837,7 @@ public:
explicit ExpressionIfNull(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIfNull, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -867,7 +847,7 @@ public:
explicit ExpressionIn(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIn, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -877,7 +857,7 @@ public:
explicit ExpressionIndexOfArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionIndexOfArray, 2, 4>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -887,7 +867,7 @@ public:
explicit ExpressionIndexOfBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionIndexOfBytes, 2, 4>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -900,7 +880,7 @@ public:
explicit ExpressionIndexOfCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionIndexOfCP, 2, 4>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -909,7 +889,7 @@ class ExpressionLet final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
void addDependencies(DepsTracker* deps) const final;
static boost::intrusive_ptr<Expression> parse(
@@ -951,7 +931,7 @@ public:
explicit ExpressionLog(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionLog, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -968,7 +948,7 @@ class ExpressionMap final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
Value serialize(bool explain) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
void addDependencies(DepsTracker* deps) const final;
static boost::intrusive_ptr<Expression> parse(
@@ -993,7 +973,7 @@ private:
class ExpressionMeta final : public Expression {
public:
Value serialize(bool explain) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
void addDependencies(DepsTracker* deps) const final;
static boost::intrusive_ptr<Expression> parse(
@@ -1017,7 +997,7 @@ public:
explicit ExpressionMillisecond(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionMillisecond, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const long long date);
@@ -1029,7 +1009,7 @@ public:
explicit ExpressionMinute(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionMinute, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const tm& tm) {
@@ -1043,7 +1023,7 @@ public:
explicit ExpressionMod(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionMod, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1053,7 +1033,7 @@ public:
explicit ExpressionMultiply(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionMultiply>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1071,7 +1051,7 @@ public:
explicit ExpressionMonth(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionMonth, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
// MySQL uses 1-12, tm uses 0-11
@@ -1086,7 +1066,7 @@ public:
explicit ExpressionNot(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionNot, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1103,7 +1083,7 @@ class ExpressionObject final : public Expression {
public:
boost::intrusive_ptr<Expression> optimize() final;
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
Value serialize(bool explain) const final;
static boost::intrusive_ptr<ExpressionObject> create(
@@ -1143,7 +1123,7 @@ public:
: ExpressionVariadic<ExpressionOr>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1164,7 +1144,7 @@ public:
const boost::intrusive_ptr<ExpressionContext>& expCtx, Value base, Value exp);
private:
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1174,7 +1154,7 @@ public:
explicit ExpressionRange(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionRange, 2, 3>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1185,7 +1165,7 @@ public:
: Expression(expCtx) {}
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1208,7 +1188,7 @@ public:
explicit ExpressionSecond(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSecond, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static inline int extract(const tm& tm) {
@@ -1222,7 +1202,7 @@ public:
explicit ExpressionSetDifference(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSetDifference, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1232,7 +1212,7 @@ public:
explicit ExpressionSetEquals(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetEquals>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
void validateArguments(const ExpressionVector& args) const final;
};
@@ -1243,7 +1223,7 @@ public:
explicit ExpressionSetIntersection(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetIntersection>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1263,7 +1243,7 @@ public:
: ExpressionFixedArity<ExpressionSetIsSubset, 2>(expCtx) {}
boost::intrusive_ptr<Expression> optimize() override;
- Value evaluateInternal() const override;
+ Value evaluate(Document root) const override;
const char* getOpName() const final;
private:
@@ -1276,7 +1256,7 @@ public:
explicit ExpressionSetUnion(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionVariadic<ExpressionSetUnion>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
bool isAssociative() const final {
@@ -1294,7 +1274,7 @@ public:
explicit ExpressionSize(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSize, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1304,7 +1284,7 @@ public:
explicit ExpressionReverseArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionReverseArray, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1314,7 +1294,7 @@ public:
explicit ExpressionSlice(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionRangedArity<ExpressionSlice, 2, 3>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1324,7 +1304,7 @@ public:
explicit ExpressionIsArray(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIsArray, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1334,7 +1314,7 @@ public:
explicit ExpressionSplit(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSplit, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1354,7 +1334,7 @@ public:
explicit ExpressionStrcasecmp(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrcasecmp, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1364,7 +1344,7 @@ public:
explicit ExpressionSubstrBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubstrBytes, 3>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const;
};
@@ -1374,7 +1354,7 @@ public:
explicit ExpressionSubstrCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubstrCP, 3>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1384,7 +1364,7 @@ public:
explicit ExpressionStrLenBytes(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrLenBytes, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1394,7 +1374,7 @@ public:
explicit ExpressionStrLenCP(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionStrLenCP, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1404,7 +1384,7 @@ public:
explicit ExpressionSubtract(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionSubtract, 2>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1415,7 +1395,7 @@ public:
: Expression(expCtx) {}
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
@@ -1437,7 +1417,7 @@ public:
explicit ExpressionToLower(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionToLower, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1447,7 +1427,7 @@ public:
explicit ExpressionToUpper(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionToUpper, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1467,7 +1447,7 @@ public:
explicit ExpressionType(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionType, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
};
@@ -1477,7 +1457,7 @@ public:
explicit ExpressionWeek(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionWeek, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const tm& tm);
@@ -1489,7 +1469,7 @@ public:
explicit ExpressionIsoWeekYear(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIsoWeekYear, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const tm& tm);
@@ -1501,7 +1481,7 @@ public:
explicit ExpressionIsoDayOfWeek(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIsoDayOfWeek, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const tm& tm);
@@ -1513,7 +1493,7 @@ public:
explicit ExpressionIsoWeek(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionIsoWeek, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
static int extract(const tm& tm);
@@ -1525,7 +1505,7 @@ public:
explicit ExpressionYear(const boost::intrusive_ptr<ExpressionContext>& expCtx)
: ExpressionFixedArity<ExpressionYear, 1>(expCtx) {}
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
const char* getOpName() const final;
// tm_year is years since 1990
@@ -1541,7 +1521,7 @@ public:
: Expression(expCtx) {}
void addDependencies(DepsTracker* deps) const final;
- Value evaluateInternal() const final;
+ Value evaluate(Document root) const final;
boost::intrusive_ptr<Expression> optimize() final;
static boost::intrusive_ptr<Expression> parse(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index a470873058a..15e7f0421b2 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -172,13 +172,13 @@ public:
/** A dummy child of ExpressionNary used for testing. */
class Testable : public ExpressionNary {
public:
- virtual Value evaluateInternal() const {
+ virtual Value evaluate(Document root) 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 (ExpressionVector::const_iterator i = vpOperand.begin(); i != vpOperand.end(); ++i) {
- values.push_back((*i)->evaluateInternal());
+ values.push_back((*i)->evaluate(root));
}
return Value(values);
}
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 68182291d3a..eab573f737f 100644
--- a/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp
+++ b/src/mongo/db/pipeline/granularity_rounder_powers_of_two.cpp
@@ -80,7 +80,7 @@ Value GranularityRounderPowersOfTwo::roundUp(Value value) {
exp = Value(63 - countLeadingZeros64(number) + 1);
}
- return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate();
+ return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document());
}
Value GranularityRounderPowersOfTwo::roundDown(Value value) {
@@ -112,7 +112,7 @@ Value GranularityRounderPowersOfTwo::roundDown(Value value) {
}
}
- return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate();
+ return ExpressionPow::create(getExpCtx(), Value(2), exp)->evaluate(Document());
}
string GranularityRounderPowersOfTwo::getName() {
diff --git a/src/mongo/db/pipeline/parsed_add_fields.cpp b/src/mongo/db/pipeline/parsed_add_fields.cpp
index 18b13c6aa61..ac605bb9a96 100644
--- a/src/mongo/db/pipeline/parsed_add_fields.cpp
+++ b/src/mongo/db/pipeline/parsed_add_fields.cpp
@@ -84,14 +84,10 @@ void ParsedAddFields::parse(const BSONObj& spec) {
}
}
-Document ParsedAddFields::applyProjection(Document inputDoc, Variables* vars) const {
- // All expressions will be evaluated in the context of the input document, before any
- // transformations have been applied.
- vars->setRoot(inputDoc);
-
+Document ParsedAddFields::applyProjection(Document inputDoc) const {
// The output doc is the same as the input doc, with the added fields.
MutableDocument output(inputDoc);
- _root->addComputedFields(&output);
+ _root->addComputedFields(&output, inputDoc);
// Pass through the metadata.
output.copyMetaDataFrom(inputDoc);
diff --git a/src/mongo/db/pipeline/parsed_add_fields.h b/src/mongo/db/pipeline/parsed_add_fields.h
index 261dbb903aa..83af2f20018 100644
--- a/src/mongo/db/pipeline/parsed_add_fields.h
+++ b/src/mongo/db/pipeline/parsed_add_fields.h
@@ -110,13 +110,7 @@ public:
* in the array "a". If there is an element in "a" that is not an object, it will be replaced
* with {"0": "hello"}. See SERVER-25200 for more details.
*/
- Document applyProjection(Document inputDoc) const final {
- auto& variables = _expCtx->variables;
- variables.setRoot(inputDoc);
- return applyProjection(inputDoc, &variables);
- }
-
- Document applyProjection(Document inputDoc, Variables* vars) const;
+ Document applyProjection(Document inputDoc) const final;
private:
/**
diff --git a/src/mongo/db/pipeline/parsed_inclusion_projection.cpp b/src/mongo/db/pipeline/parsed_inclusion_projection.cpp
index 765ee6f125b..fb486543621 100644
--- a/src/mongo/db/pipeline/parsed_inclusion_projection.cpp
+++ b/src/mongo/db/pipeline/parsed_inclusion_projection.cpp
@@ -141,29 +141,29 @@ Value InclusionNode::applyInclusionsToValue(Value inputValue) const {
}
}
-void InclusionNode::addComputedFields(MutableDocument* outputDoc) const {
+void InclusionNode::addComputedFields(MutableDocument* outputDoc, Document root) const {
for (auto&& field : _orderToProcessAdditionsAndChildren) {
auto childIt = _children.find(field);
if (childIt != _children.end()) {
outputDoc->setField(field,
- childIt->second->addComputedFields(outputDoc->peek()[field]));
+ childIt->second->addComputedFields(outputDoc->peek()[field], root));
} else {
auto expressionIt = _expressions.find(field);
invariant(expressionIt != _expressions.end());
- outputDoc->setField(field, expressionIt->second->evaluate());
+ outputDoc->setField(field, expressionIt->second->evaluate(root));
}
}
}
-Value InclusionNode::addComputedFields(Value inputValue) const {
+Value InclusionNode::addComputedFields(Value inputValue, Document root) const {
if (inputValue.getType() == BSONType::Object) {
MutableDocument outputDoc(inputValue.getDocument());
- addComputedFields(&outputDoc);
+ addComputedFields(&outputDoc, root);
return outputDoc.freezeToValue();
} else if (inputValue.getType() == BSONType::Array) {
std::vector<Value> values = inputValue.getArray();
for (auto it = values.begin(); it != values.end(); ++it) {
- *it = addComputedFields(*it);
+ *it = addComputedFields(*it, root);
}
return Value(std::move(values));
} else {
@@ -172,7 +172,7 @@ Value InclusionNode::addComputedFields(Value inputValue) const {
// document of all the computed values. This case represents applying a projection like
// {"a.b": {$literal: 1}} to the document {a: 1}. This should yield {a: {b: 1}}.
MutableDocument outputDoc;
- addComputedFields(&outputDoc);
+ addComputedFields(&outputDoc, root);
return outputDoc.freezeToValue();
}
// We didn't have any expressions, so just return the missing value.
@@ -349,14 +349,12 @@ void ParsedInclusionProjection::parse(const BSONObj& spec) {
atLeastOneFieldInOutput);
}
-Document ParsedInclusionProjection::applyProjection(Document inputDoc, Variables* vars) const {
+Document ParsedInclusionProjection::applyProjection(Document inputDoc) const {
// All expressions will be evaluated in the context of the input document, before any
// transformations have been applied.
- vars->setRoot(inputDoc);
-
MutableDocument output;
_root->applyInclusions(inputDoc, &output);
- _root->addComputedFields(&output);
+ _root->addComputedFields(&output, inputDoc);
// Always pass through the metadata.
output.copyMetaDataFrom(inputDoc);
diff --git a/src/mongo/db/pipeline/parsed_inclusion_projection.h b/src/mongo/db/pipeline/parsed_inclusion_projection.h
index f86b9970519..3077f3f4b37 100644
--- a/src/mongo/db/pipeline/parsed_inclusion_projection.h
+++ b/src/mongo/db/pipeline/parsed_inclusion_projection.h
@@ -88,7 +88,7 @@ public:
/**
* Add computed fields to 'outputDoc'.
*/
- void addComputedFields(MutableDocument* outputDoc) const;
+ void addComputedFields(MutableDocument* outputDoc, Document root) const;
/**
* Creates the child if it doesn't already exist. 'field' is not allowed to be dotted.
@@ -139,7 +139,7 @@ private:
// Helpers for the Document versions above. These will apply the transformation recursively to
// each element of any arrays, and ensure non-documents are handled appropriately.
Value applyInclusionsToValue(Value inputVal) const;
- Value addComputedFields(Value inputVal) const;
+ Value addComputedFields(Value inputVal, Document root) const;
/**
* Returns nullptr if no such child exists.
@@ -242,13 +242,7 @@ public:
* Arrays will be traversed, with any dotted/nested exclusions or computed fields applied to
* each element in the array.
*/
- Document applyProjection(Document inputDoc) const final {
- auto& vars = _expCtx->variables;
- vars.setRoot(inputDoc);
- return applyProjection(inputDoc, &vars);
- }
-
- Document applyProjection(Document inputDoc, Variables* vars) const;
+ Document applyProjection(Document inputDoc) const final;
private:
/**
diff --git a/src/mongo/db/pipeline/variables.cpp b/src/mongo/db/pipeline/variables.cpp
index ba1b42e4fb1..53156f92e4b 100644
--- a/src/mongo/db/pipeline/variables.cpp
+++ b/src/mongo/db/pipeline/variables.cpp
@@ -109,12 +109,12 @@ void Variables::setValue(Id id, const Value& value) {
_valueList[id] = value;
}
-Value Variables::getValue(Id id) const {
+Value Variables::getValue(Id id, Document root) const {
if (id < 0) {
// This is a reserved id for a builtin variable.
switch (id) {
case Variables::kRootId:
- return Value(_root);
+ return Value(root);
case Variables::kRemoveId:
return Value();
default:
@@ -128,13 +128,13 @@ Value Variables::getValue(Id id) const {
return _valueList[id];
}
-Document Variables::getDocument(Id id) const {
+Document Variables::getDocument(Id id, Document root) const {
if (id == Variables::kRootId) {
// For the common case of ROOT, avoid round-tripping through Value.
- return _root;
+ return root;
}
- const Value var = getValue(id);
+ const Value var = getValue(id, root);
if (var.getType() == Object)
return var.getDocument();
diff --git a/src/mongo/db/pipeline/variables.h b/src/mongo/db/pipeline/variables.h
index b1e0f0c7deb..98ffd2fe595 100644
--- a/src/mongo/db/pipeline/variables.h
+++ b/src/mongo/db/pipeline/variables.h
@@ -72,33 +72,22 @@ public:
static const StringMap<Id> kBuiltinVarNameToId;
/**
- * Use this instead of setValue for setting ROOT
- */
- void setRoot(const Document& root) {
- _root = root;
- }
- void clearRoot() {
- _root = Document();
- }
- const Document& getRoot() const {
- return _root;
- }
-
- /**
* Sets the value of a user-defined variable. Illegal to use with the reserved builtin variables
* defined above.
*/
void setValue(Variables::Id id, const Value& value);
/**
- * Gets the value of a user-defined or system variable.
+ * Gets the value of a user-defined or system variable. If the 'id' provided represents the
+ * special ROOT variable, then we return 'root' in Value form.
*/
- Value getValue(Variables::Id id) const;
+ Value getValue(Variables::Id id, Document root) const;
/**
- * Returns Document() for non-document values, but otherwise identical to getValue().
+ * Returns Document() for non-document values, but otherwise identical to getValue(). If the
+ * 'id' provided represents the special ROOT variable, then we return 'root'.
*/
- Document getDocument(Variables::Id id) const;
+ Document getDocument(Variables::Id id, Document root) const;
IdGenerator* useIdGenerator() {
return &_idGenerator;
@@ -106,7 +95,6 @@ public:
private:
- Document _root;
IdGenerator _idGenerator;
std::vector<Value> _valueList;
};