mirror of https://gitee.com/bigwinds/arangodb
added AggregateNode.*
This commit is contained in:
parent
50fa5a2138
commit
91e8884518
|
@ -29,6 +29,7 @@
|
|||
#define ARANGODB_AQL_AGGREGATE_BLOCK_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/ExecutionBlock.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
|
||||
|
@ -38,7 +39,6 @@ namespace triagens {
|
|||
}
|
||||
|
||||
namespace aql {
|
||||
|
||||
class AqlItemBlock;
|
||||
class ExecutionEngine;
|
||||
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief AggregateNode
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "AggregateNode.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/ExecutionPlan.h"
|
||||
#include "Aql/WalkerWorker.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::aql;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- methods of AggregateNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
AggregateNode::AggregateNode (ExecutionPlan* plan,
|
||||
triagens::basics::Json const& base,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
bool count,
|
||||
bool isDistinctCommand)
|
||||
: ExecutionNode(plan, base),
|
||||
_options(base),
|
||||
_aggregateVariables(aggregateVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
_variableMap(variableMap),
|
||||
_count(count),
|
||||
_isDistinctCommand(isDistinctCommand) {
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toJson, for AggregateNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::toJsonHelper (triagens::basics::Json& nodes,
|
||||
TRI_memory_zone_t* zone,
|
||||
bool verbose) const {
|
||||
|
||||
triagens::basics::Json json(ExecutionNode::toJsonHelperGeneric(nodes, zone, verbose)); // call base class method
|
||||
|
||||
if (json.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
triagens::basics::Json values(triagens::basics::Json::Array, _aggregateVariables.size());
|
||||
|
||||
for (auto it = _aggregateVariables.begin(); it != _aggregateVariables.end(); ++it) {
|
||||
triagens::basics::Json variable(triagens::basics::Json::Object);
|
||||
variable("outVariable", (*it).first->toJson())
|
||||
("inVariable", (*it).second->toJson());
|
||||
values(variable);
|
||||
}
|
||||
json("aggregates", values);
|
||||
|
||||
// expression variable might be empty
|
||||
if (_expressionVariable != nullptr) {
|
||||
json("expressionVariable", _expressionVariable->toJson());
|
||||
}
|
||||
|
||||
// output variable might be empty
|
||||
if (_outVariable != nullptr) {
|
||||
json("outVariable", _outVariable->toJson());
|
||||
}
|
||||
|
||||
if (! _keepVariables.empty()) {
|
||||
triagens::basics::Json values(triagens::basics::Json::Array, _keepVariables.size());
|
||||
for (auto it = _keepVariables.begin(); it != _keepVariables.end(); ++it) {
|
||||
triagens::basics::Json variable(triagens::basics::Json::Object);
|
||||
variable("variable", (*it)->toJson());
|
||||
values(variable);
|
||||
}
|
||||
json("keepVariables", values);
|
||||
}
|
||||
|
||||
json("count", triagens::basics::Json(_count));
|
||||
json("isDistinctCommand", triagens::basics::Json(_isDistinctCommand));
|
||||
json("specialized", triagens::basics::Json(_specialized));
|
||||
|
||||
_options.toJson(json, zone);
|
||||
|
||||
// And add it:
|
||||
nodes(json);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone ExecutionNode recursively
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* AggregateNode::clone (ExecutionPlan* plan,
|
||||
bool withDependencies,
|
||||
bool withProperties) const {
|
||||
auto outVariable = _outVariable;
|
||||
auto expressionVariable = _expressionVariable;
|
||||
auto aggregateVariables = _aggregateVariables;
|
||||
|
||||
if (withProperties) {
|
||||
if (expressionVariable != nullptr) {
|
||||
expressionVariable = plan->getAst()->variables()->createVariable(expressionVariable);
|
||||
}
|
||||
|
||||
if (outVariable != nullptr) {
|
||||
outVariable = plan->getAst()->variables()->createVariable(outVariable);
|
||||
}
|
||||
|
||||
// need to re-create all variables
|
||||
aggregateVariables.clear();
|
||||
|
||||
for (auto& it : _aggregateVariables) {
|
||||
auto out = plan->getAst()->variables()->createVariable(it.first);
|
||||
auto in = plan->getAst()->variables()->createVariable(it.second);
|
||||
aggregateVariables.emplace_back(std::make_pair(out, in));
|
||||
}
|
||||
}
|
||||
|
||||
auto c = new AggregateNode(
|
||||
plan,
|
||||
_id,
|
||||
_options,
|
||||
aggregateVariables,
|
||||
expressionVariable,
|
||||
outVariable,
|
||||
_keepVariables,
|
||||
_variableMap,
|
||||
_count,
|
||||
_isDistinctCommand
|
||||
);
|
||||
|
||||
// specialize the cloned node
|
||||
if (isSpecialized()) {
|
||||
c->specialized();
|
||||
}
|
||||
|
||||
cloneHelper(c, plan, withDependencies, withProperties);
|
||||
|
||||
return static_cast<ExecutionNode*>(c);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct UserVarFinder final : public WalkerWorker<ExecutionNode> {
|
||||
UserVarFinder (int mindepth)
|
||||
: mindepth(mindepth), depth(-1) {
|
||||
}
|
||||
|
||||
~UserVarFinder () {
|
||||
}
|
||||
|
||||
std::vector<Variable const*> userVars;
|
||||
int mindepth; // minimal depth to consider
|
||||
int depth;
|
||||
|
||||
bool enterSubquery (ExecutionNode*, ExecutionNode*) override final {
|
||||
return false;
|
||||
}
|
||||
|
||||
void after (ExecutionNode* en) override final {
|
||||
if (en->getType() == ExecutionNode::SINGLETON) {
|
||||
depth = 0;
|
||||
}
|
||||
else if (en->getType() == ExecutionNode::ENUMERATE_COLLECTION ||
|
||||
en->getType() == ExecutionNode::INDEX ||
|
||||
en->getType() == ExecutionNode::INDEX_RANGE ||
|
||||
en->getType() == ExecutionNode::ENUMERATE_LIST ||
|
||||
en->getType() == ExecutionNode::AGGREGATE) {
|
||||
depth += 1;
|
||||
}
|
||||
// Now depth is set correct for this node.
|
||||
if (depth >= mindepth) {
|
||||
auto const& vars = en->getVariablesSetHere();
|
||||
for (auto const& v : vars) {
|
||||
if (v->isUserDefined()) {
|
||||
userVars.emplace_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, returning a vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> AggregateNode::getVariablesUsedHere () const {
|
||||
std::unordered_set<Variable const*> v;
|
||||
// actual work is done by that method
|
||||
getVariablesUsedHere(v);
|
||||
|
||||
// copy result into vector
|
||||
std::vector<Variable const*> vv;
|
||||
vv.reserve(v.size());
|
||||
for (auto const& x : v) {
|
||||
vv.emplace_back(x);
|
||||
}
|
||||
return vv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, modifying the set in-place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::getVariablesUsedHere (std::unordered_set<Variable const*>& vars) const {
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
vars.emplace(p.second);
|
||||
}
|
||||
|
||||
if (_expressionVariable != nullptr) {
|
||||
vars.emplace(_expressionVariable);
|
||||
}
|
||||
|
||||
if (_outVariable != nullptr && ! _count) {
|
||||
if (_keepVariables.empty()) {
|
||||
// Here we have to find all user defined variables in this query
|
||||
// amongst our dependencies:
|
||||
UserVarFinder finder(1);
|
||||
auto myselfAsNonConst = const_cast<AggregateNode*>(this);
|
||||
myselfAsNonConst->walk(&finder);
|
||||
if (finder.depth == 1) {
|
||||
// we are top level, let's run again with mindepth = 0
|
||||
finder.userVars.clear();
|
||||
finder.mindepth = 0;
|
||||
finder.depth = -1;
|
||||
finder.reset();
|
||||
myselfAsNonConst->walk(&finder);
|
||||
}
|
||||
for (auto& x : finder.userVars) {
|
||||
vars.emplace(x);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& x : _keepVariables) {
|
||||
vars.emplace(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief estimateCost
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double AggregateNode::estimateCost (size_t& nrItems) const {
|
||||
double depCost = _dependencies.at(0)->getCost(nrItems);
|
||||
|
||||
// As in the FilterNode case, we are pessimistic here by not reducing the
|
||||
// nrItems much, since the worst case for COLLECT is to return as many items
|
||||
// as there are input items. In any case, we have to look at all incoming
|
||||
// items, and in particular in the COLLECT ... INTO ... case, we have
|
||||
// to actually hand on all data anyway, albeit not as separate items.
|
||||
// Nevertheless, the optimizer does not do much with AggregateNodes
|
||||
// and thus this potential overestimation does not really matter.
|
||||
|
||||
|
||||
if (_count && _aggregateVariables.empty()) {
|
||||
// we are known to only produce a single output row
|
||||
nrItems = 1;
|
||||
}
|
||||
else {
|
||||
// we do not know how many rows the COLLECT with produce...
|
||||
// the worst case is that there will be as many output rows as input rows
|
||||
if (nrItems >= 10) {
|
||||
// we assume that the collect will reduce the number of results at least somewhat
|
||||
nrItems = static_cast<size_t>(nrItems * 0.80);
|
||||
}
|
||||
}
|
||||
|
||||
return depCost + nrItems;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
||||
// End:
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief AggregateNode
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_AQL_AGGREGATE_NODE_H
|
||||
#define ARANGODB_AQL_AGGREGATE_NODE_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/types.h"
|
||||
#include "Aql/Variable.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
class ExecutionBlock;
|
||||
class ExecutionPlan;
|
||||
class RedundantCalculationsReplacer;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class AggregateNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief class AggregateNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AggregateNode : public ExecutionNode {
|
||||
|
||||
friend class ExecutionNode;
|
||||
friend class ExecutionBlock;
|
||||
friend class SortedAggregateBlock;
|
||||
friend class HashedAggregateBlock;
|
||||
friend class RedundantCalculationsReplacer;
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public:
|
||||
|
||||
AggregateNode (ExecutionPlan* plan,
|
||||
size_t id,
|
||||
AggregationOptions const& options,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
bool count,
|
||||
bool isDistinctCommand)
|
||||
: ExecutionNode(plan, id),
|
||||
_options(options),
|
||||
_aggregateVariables(aggregateVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
_variableMap(variableMap),
|
||||
_count(count),
|
||||
_isDistinctCommand(isDistinctCommand),
|
||||
_specialized(false) {
|
||||
|
||||
// outVariable can be a nullptr, but only if _count is not set
|
||||
TRI_ASSERT(! _count || _outVariable != nullptr);
|
||||
}
|
||||
|
||||
AggregateNode (ExecutionPlan*,
|
||||
triagens::basics::Json const& base,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
bool count,
|
||||
bool isDistinctCommand);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the type of the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NodeType getType () const override final {
|
||||
return AGGREGATE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node requires an additional post SORT
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isDistinctCommand () const {
|
||||
return _isDistinctCommand;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node is specialized
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isSpecialized () const {
|
||||
return _specialized;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void specialized () {
|
||||
_specialized = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions::AggregationMethod aggregationMethod () const {
|
||||
return _options.method;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void aggregationMethod (AggregationOptions::AggregationMethod method) {
|
||||
_options.method = method;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions const& getOptions () const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions& getOptions () {
|
||||
return _options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief export to JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void toJsonHelper (triagens::basics::Json&,
|
||||
TRI_memory_zone_t*,
|
||||
bool) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone ExecutionNode recursively
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* clone (ExecutionPlan* plan,
|
||||
bool withDependencies,
|
||||
bool withProperties) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief estimateCost
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double estimateCost (size_t&) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the count flag is set
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool count () const {
|
||||
return _count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node has an outVariable (i.e. INTO ...)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool hasOutVariable () const {
|
||||
return _outVariable != nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the out variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* outVariable () const {
|
||||
return _outVariable;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clear the out variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void clearOutVariable () {
|
||||
TRI_ASSERT(_outVariable != nullptr);
|
||||
_outVariable = nullptr;
|
||||
_count = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node has an expression variable (i.e. INTO ...
|
||||
/// = expr)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool hasExpressionVariable () const {
|
||||
return _expressionVariable != nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the expression variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setExpressionVariable (Variable const* variable) {
|
||||
TRI_ASSERT(! hasExpressionVariable());
|
||||
_expressionVariable = variable;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the variable map
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap () const {
|
||||
return _variableMap;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get all aggregate variables (out, in)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables () const {
|
||||
return _aggregateVariables;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, returning a vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> getVariablesUsedHere () const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, modifying the set in-place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getVariablesUsedHere (std::unordered_set<Variable const*>& vars) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesSetHere
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> getVariablesSetHere () const override final {
|
||||
std::vector<Variable const*> v;
|
||||
size_t const n = _aggregateVariables.size() + (_outVariable == nullptr ? 0 : 1);
|
||||
v.reserve(n);
|
||||
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
v.emplace_back(p.first);
|
||||
}
|
||||
if (_outVariable != nullptr) {
|
||||
v.emplace_back(_outVariable);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief options for the aggregation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions _options;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input/output variables for the aggregation (out, in)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input expression variable (might be null)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* _expressionVariable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief output variable to write to (might be null)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* _outVariable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of variables to keep if INTO is used
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> _keepVariables;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief map of all variable ids and names (needed to construct group data)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<VariableId, std::string const> const _variableMap;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief COUNTing node?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _count;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node requires an additional post-SORT
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool const _isDistinctCommand;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node is specialized
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _specialized;
|
||||
};
|
||||
|
||||
} // namespace triagens::aql
|
||||
} // namespace triagens
|
||||
|
||||
#endif
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
||||
// End:
|
||||
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "Aql/ExecutionEngine.h"
|
||||
#include "Aql/AggregateBlock.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/BasicBlocks.h"
|
||||
#include "Aql/CalculationBlock.h"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ExecutionNode.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/ClusterNodes.h"
|
||||
#include "Aql/Collection.h"
|
||||
|
@ -1842,271 +1843,6 @@ double FilterNode::estimateCost (size_t& nrItems) const {
|
|||
return depCost + nrItems;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- methods of AggregateNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
AggregateNode::AggregateNode (ExecutionPlan* plan,
|
||||
triagens::basics::Json const& base,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
bool count,
|
||||
bool isDistinctCommand)
|
||||
: ExecutionNode(plan, base),
|
||||
_options(base),
|
||||
_aggregateVariables(aggregateVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
_variableMap(variableMap),
|
||||
_count(count),
|
||||
_isDistinctCommand(isDistinctCommand) {
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toJson, for AggregateNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::toJsonHelper (triagens::basics::Json& nodes,
|
||||
TRI_memory_zone_t* zone,
|
||||
bool verbose) const {
|
||||
|
||||
triagens::basics::Json json(ExecutionNode::toJsonHelperGeneric(nodes, zone, verbose)); // call base class method
|
||||
|
||||
if (json.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
triagens::basics::Json values(triagens::basics::Json::Array, _aggregateVariables.size());
|
||||
|
||||
for (auto it = _aggregateVariables.begin(); it != _aggregateVariables.end(); ++it) {
|
||||
triagens::basics::Json variable(triagens::basics::Json::Object);
|
||||
variable("outVariable", (*it).first->toJson())
|
||||
("inVariable", (*it).second->toJson());
|
||||
values(variable);
|
||||
}
|
||||
json("aggregates", values);
|
||||
|
||||
// expression variable might be empty
|
||||
if (_expressionVariable != nullptr) {
|
||||
json("expressionVariable", _expressionVariable->toJson());
|
||||
}
|
||||
|
||||
// output variable might be empty
|
||||
if (_outVariable != nullptr) {
|
||||
json("outVariable", _outVariable->toJson());
|
||||
}
|
||||
|
||||
if (! _keepVariables.empty()) {
|
||||
triagens::basics::Json values(triagens::basics::Json::Array, _keepVariables.size());
|
||||
for (auto it = _keepVariables.begin(); it != _keepVariables.end(); ++it) {
|
||||
triagens::basics::Json variable(triagens::basics::Json::Object);
|
||||
variable("variable", (*it)->toJson());
|
||||
values(variable);
|
||||
}
|
||||
json("keepVariables", values);
|
||||
}
|
||||
|
||||
json("count", triagens::basics::Json(_count));
|
||||
json("isDistinctCommand", triagens::basics::Json(_isDistinctCommand));
|
||||
json("specialized", triagens::basics::Json(_specialized));
|
||||
|
||||
_options.toJson(json, zone);
|
||||
|
||||
// And add it:
|
||||
nodes(json);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone ExecutionNode recursively
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* AggregateNode::clone (ExecutionPlan* plan,
|
||||
bool withDependencies,
|
||||
bool withProperties) const {
|
||||
auto outVariable = _outVariable;
|
||||
auto expressionVariable = _expressionVariable;
|
||||
auto aggregateVariables = _aggregateVariables;
|
||||
|
||||
if (withProperties) {
|
||||
if (expressionVariable != nullptr) {
|
||||
expressionVariable = plan->getAst()->variables()->createVariable(expressionVariable);
|
||||
}
|
||||
|
||||
if (outVariable != nullptr) {
|
||||
outVariable = plan->getAst()->variables()->createVariable(outVariable);
|
||||
}
|
||||
|
||||
// need to re-create all variables
|
||||
aggregateVariables.clear();
|
||||
|
||||
for (auto& it : _aggregateVariables) {
|
||||
auto out = plan->getAst()->variables()->createVariable(it.first);
|
||||
auto in = plan->getAst()->variables()->createVariable(it.second);
|
||||
aggregateVariables.emplace_back(std::make_pair(out, in));
|
||||
}
|
||||
}
|
||||
|
||||
auto c = new AggregateNode(
|
||||
plan,
|
||||
_id,
|
||||
_options,
|
||||
aggregateVariables,
|
||||
expressionVariable,
|
||||
outVariable,
|
||||
_keepVariables,
|
||||
_variableMap,
|
||||
_count,
|
||||
_isDistinctCommand
|
||||
);
|
||||
|
||||
// specialize the cloned node
|
||||
if (isSpecialized()) {
|
||||
c->specialized();
|
||||
}
|
||||
|
||||
cloneHelper(c, plan, withDependencies, withProperties);
|
||||
|
||||
return static_cast<ExecutionNode*>(c);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct UserVarFinder final : public WalkerWorker<ExecutionNode> {
|
||||
UserVarFinder (int mindepth)
|
||||
: mindepth(mindepth), depth(-1) {
|
||||
}
|
||||
|
||||
~UserVarFinder () {
|
||||
}
|
||||
|
||||
std::vector<Variable const*> userVars;
|
||||
int mindepth; // minimal depth to consider
|
||||
int depth;
|
||||
|
||||
bool enterSubquery (ExecutionNode*, ExecutionNode*) override final {
|
||||
return false;
|
||||
}
|
||||
|
||||
void after (ExecutionNode* en) override final {
|
||||
if (en->getType() == ExecutionNode::SINGLETON) {
|
||||
depth = 0;
|
||||
}
|
||||
else if (en->getType() == ExecutionNode::ENUMERATE_COLLECTION ||
|
||||
en->getType() == ExecutionNode::INDEX ||
|
||||
en->getType() == ExecutionNode::INDEX_RANGE ||
|
||||
en->getType() == ExecutionNode::ENUMERATE_LIST ||
|
||||
en->getType() == ExecutionNode::AGGREGATE) {
|
||||
depth += 1;
|
||||
}
|
||||
// Now depth is set correct for this node.
|
||||
if (depth >= mindepth) {
|
||||
auto const& vars = en->getVariablesSetHere();
|
||||
for (auto const& v : vars) {
|
||||
if (v->isUserDefined()) {
|
||||
userVars.emplace_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, returning a vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> AggregateNode::getVariablesUsedHere () const {
|
||||
std::unordered_set<Variable const*> v;
|
||||
// actual work is done by that method
|
||||
getVariablesUsedHere(v);
|
||||
|
||||
// copy result into vector
|
||||
std::vector<Variable const*> vv;
|
||||
vv.reserve(v.size());
|
||||
for (auto const& x : v) {
|
||||
vv.emplace_back(x);
|
||||
}
|
||||
return vv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, modifying the set in-place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::getVariablesUsedHere (std::unordered_set<Variable const*>& vars) const {
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
vars.emplace(p.second);
|
||||
}
|
||||
|
||||
if (_expressionVariable != nullptr) {
|
||||
vars.emplace(_expressionVariable);
|
||||
}
|
||||
|
||||
if (_outVariable != nullptr && ! _count) {
|
||||
if (_keepVariables.empty()) {
|
||||
// Here we have to find all user defined variables in this query
|
||||
// amongst our dependencies:
|
||||
UserVarFinder finder(1);
|
||||
auto myselfAsNonConst = const_cast<AggregateNode*>(this);
|
||||
myselfAsNonConst->walk(&finder);
|
||||
if (finder.depth == 1) {
|
||||
// we are top level, let's run again with mindepth = 0
|
||||
finder.userVars.clear();
|
||||
finder.mindepth = 0;
|
||||
finder.depth = -1;
|
||||
finder.reset();
|
||||
myselfAsNonConst->walk(&finder);
|
||||
}
|
||||
for (auto& x : finder.userVars) {
|
||||
vars.emplace(x);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& x : _keepVariables) {
|
||||
vars.emplace(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief estimateCost
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double AggregateNode::estimateCost (size_t& nrItems) const {
|
||||
double depCost = _dependencies.at(0)->getCost(nrItems);
|
||||
|
||||
// As in the FilterNode case, we are pessimistic here by not reducing the
|
||||
// nrItems much, since the worst case for COLLECT is to return as many items
|
||||
// as there are input items. In any case, we have to look at all incoming
|
||||
// items, and in particular in the COLLECT ... INTO ... case, we have
|
||||
// to actually hand on all data anyway, albeit not as separate items.
|
||||
// Nevertheless, the optimizer does not do much with AggregateNodes
|
||||
// and thus this potential overestimation does not really matter.
|
||||
|
||||
|
||||
if (_count && _aggregateVariables.empty()) {
|
||||
// we are known to only produce a single output row
|
||||
nrItems = 1;
|
||||
}
|
||||
else {
|
||||
// we do not know how many rows the COLLECT with produce...
|
||||
// the worst case is that there will be as many output rows as input rows
|
||||
if (nrItems >= 10) {
|
||||
// we assume that the collect will reduce the number of results at least somewhat
|
||||
nrItems = static_cast<size_t>(nrItems * 0.80);
|
||||
}
|
||||
}
|
||||
|
||||
return depCost + nrItems;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- methods of ReturnNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#define ARANGODB_AQL_EXECUTION_NODE_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/Expression.h"
|
||||
#include "Aql/types.h"
|
||||
#include "Aql/Variable.h"
|
||||
|
@ -1750,310 +1748,6 @@ namespace triagens {
|
|||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class AggregateNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief class AggregateNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AggregateNode : public ExecutionNode {
|
||||
|
||||
friend class ExecutionNode;
|
||||
friend class ExecutionBlock;
|
||||
friend class SortedAggregateBlock;
|
||||
friend class HashedAggregateBlock;
|
||||
friend class RedundantCalculationsReplacer;
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public:
|
||||
|
||||
AggregateNode (ExecutionPlan* plan,
|
||||
size_t id,
|
||||
AggregationOptions const& options,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
bool count,
|
||||
bool isDistinctCommand)
|
||||
: ExecutionNode(plan, id),
|
||||
_options(options),
|
||||
_aggregateVariables(aggregateVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
_variableMap(variableMap),
|
||||
_count(count),
|
||||
_isDistinctCommand(isDistinctCommand),
|
||||
_specialized(false) {
|
||||
|
||||
// outVariable can be a nullptr, but only if _count is not set
|
||||
TRI_ASSERT(! _count || _outVariable != nullptr);
|
||||
}
|
||||
|
||||
AggregateNode (ExecutionPlan*,
|
||||
triagens::basics::Json const& base,
|
||||
Variable const* expressionVariable,
|
||||
Variable const* outVariable,
|
||||
std::vector<Variable const*> const& keepVariables,
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables,
|
||||
bool count,
|
||||
bool isDistinctCommand);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the type of the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NodeType getType () const override final {
|
||||
return AGGREGATE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node requires an additional post SORT
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isDistinctCommand () const {
|
||||
return _isDistinctCommand;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node is specialized
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isSpecialized () const {
|
||||
return _specialized;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void specialized () {
|
||||
_specialized = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions::AggregationMethod aggregationMethod () const {
|
||||
return _options.method;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void aggregationMethod (AggregationOptions::AggregationMethod method) {
|
||||
_options.method = method;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions const& getOptions () const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions& getOptions () {
|
||||
return _options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief export to JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void toJsonHelper (triagens::basics::Json&,
|
||||
TRI_memory_zone_t*,
|
||||
bool) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone ExecutionNode recursively
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* clone (ExecutionPlan* plan,
|
||||
bool withDependencies,
|
||||
bool withProperties) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief estimateCost
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double estimateCost (size_t&) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the count flag is set
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool count () const {
|
||||
return _count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node has an outVariable (i.e. INTO ...)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool hasOutVariable () const {
|
||||
return _outVariable != nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the out variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* outVariable () const {
|
||||
return _outVariable;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clear the out variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void clearOutVariable () {
|
||||
TRI_ASSERT(_outVariable != nullptr);
|
||||
_outVariable = nullptr;
|
||||
_count = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node has an expression variable (i.e. INTO ...
|
||||
/// = expr)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool hasExpressionVariable () const {
|
||||
return _expressionVariable != nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the expression variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setExpressionVariable (Variable const* variable) {
|
||||
TRI_ASSERT(! hasExpressionVariable());
|
||||
_expressionVariable = variable;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the variable map
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<VariableId, std::string const> const& variableMap () const {
|
||||
return _variableMap;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get all aggregate variables (out, in)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const& aggregateVariables () const {
|
||||
return _aggregateVariables;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, returning a vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> getVariablesUsedHere () const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesUsedHere, modifying the set in-place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getVariablesUsedHere (std::unordered_set<Variable const*>& vars) const override final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getVariablesSetHere
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> getVariablesSetHere () const override final {
|
||||
std::vector<Variable const*> v;
|
||||
size_t const n = _aggregateVariables.size() + (_outVariable == nullptr ? 0 : 1);
|
||||
v.reserve(n);
|
||||
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
v.emplace_back(p.first);
|
||||
}
|
||||
if (_outVariable != nullptr) {
|
||||
v.emplace_back(_outVariable);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief options for the aggregation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions _options;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input/output variables for the aggregation (out, in)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input expression variable (might be null)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* _expressionVariable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief output variable to write to (might be null)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* _outVariable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of variables to keep if INTO is used
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> _keepVariables;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief map of all variable ids and names (needed to construct group data)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<VariableId, std::string const> const _variableMap;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief COUNTing node?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _count;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node requires an additional post-SORT
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool const _isDistinctCommand;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node is specialized
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _specialized;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class ReturnNode
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ExecutionPlan.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/AstNode.h"
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
class AggregateNode;
|
||||
class Ast;
|
||||
struct AstNode;
|
||||
class CalculationNode;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/OptimizerRules.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/ClusterNodes.h"
|
||||
#include "Aql/ConditionFinder.h"
|
||||
|
|
|
@ -61,6 +61,7 @@ add_executable(
|
|||
ApplicationServer/ApplicationFeature.cpp
|
||||
ApplicationServer/ApplicationServer.cpp
|
||||
Aql/AggregateBlock.cpp
|
||||
Aql/AggregateNode.cpp
|
||||
Aql/AggregationOptions.cpp
|
||||
Aql/AqlItemBlock.cpp
|
||||
Aql/AqlItemBlockManager.cpp
|
||||
|
|
|
@ -19,6 +19,7 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/ApplicationServer/ApplicationFeature.cpp \
|
||||
arangod/ApplicationServer/ApplicationServer.cpp \
|
||||
arangod/Aql/AggregateBlock.cpp \
|
||||
arangod/Aql/AggregateNode.cpp \
|
||||
arangod/Aql/AggregationOptions.cpp \
|
||||
arangod/Aql/AqlItemBlock.cpp \
|
||||
arangod/Aql/AqlItemBlockManager.cpp \
|
||||
|
|
Loading…
Reference in New Issue