diff --git a/arangod/Aql/ExecutionNode.cpp b/arangod/Aql/ExecutionNode.cpp index 04a82d6b63..9fd620d310 100644 --- a/arangod/Aql/ExecutionNode.cpp +++ b/arangod/Aql/ExecutionNode.cpp @@ -1269,12 +1269,46 @@ ExecutionNode* EnumerateListNode::clone (ExecutionPlan* plan, double EnumerateListNode::estimateCost (size_t& nrItems) const { size_t incoming = 0; double depCost = _dependencies.at(0)->getCost(incoming); - nrItems = 100*incoming; - return depCost + 100.0 * incoming; + // Well, what can we say? The length of the list can in general // only be determined at runtime... If we were to know that this // list is constant, then we could maybe multiply by the length // here... For the time being, we assume 100 + size_t length = 100; + + auto setter = _plan->getVarSetBy(_inVariable->id); + + if (setter != nullptr && + setter->getType() == ExecutionNode::CALCULATION) { + // list variable introduced by a calculation + auto expression = static_cast(setter)->expression(); + + if (expression != nullptr) { + auto node = expression->node(); + + if (node->type == NODE_TYPE_ARRAY) { + // this one is easy + length = node->numMembers(); + } + if (node->type == NODE_TYPE_RANGE) { + auto low = node->getMember(0); + auto high = node->getMember(1); + + if (low->isConstant() && + high->isConstant() && + (low->isValueType(VALUE_TYPE_INT) || low->isValueType(VALUE_TYPE_DOUBLE)) && + (high->isValueType(VALUE_TYPE_INT) || high->isValueType(VALUE_TYPE_DOUBLE))) { + // create a temporary range to determine the size + Range range(low->getIntValue(), high->getIntValue()); + + length = range.size(); + } + } + } + } + + nrItems = length * incoming; + return depCost + static_cast(length) * incoming; } // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/V8Expression.cpp b/arangod/Aql/V8Expression.cpp index b67d4ece5a..ad7f966638 100644 --- a/arangod/Aql/V8Expression.cpp +++ b/arangod/Aql/V8Expression.cpp @@ -78,7 +78,7 @@ AqlValue V8Expression::execute (v8::Isolate* isolate, std::vector const& vars, std::vector const& regs) { size_t const n = vars.size(); - TRI_ASSERT_EXPESNIVE(regs.size() == n); // assert same vector length + TRI_ASSERT_EXPENSIVE(regs.size() == n); // assert same vector length bool const attributesPresent = ! attributes.empty(); @@ -88,9 +88,7 @@ AqlValue V8Expression::execute (v8::Isolate* isolate, auto const varname = vars[i]->name; auto reg = regs[i]; - TRI_ASSERT(! argv[reg].isEmpty()); - - auto type = argv[startPos + reg]._type; + TRI_ASSERT_EXPENSIVE(! argv[reg].isEmpty()); if (attributesPresent && argv[startPos + reg]._type == AqlValue::JSON) { // check if we can get away with constructing a partial JSON object