diff options
Diffstat (limited to 'src/mongo')
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; }; |