mirror of https://gitee.com/bigwinds/arangodb
refactoring for Aql COLLECT
This commit is contained in:
parent
d58d1dd9dc
commit
ad1163e3bb
|
@ -573,6 +573,26 @@ AstNode* Ast::createNodeCollectCount(AstNode const* list, char const* name,
|
|||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST collect node, AGGREGATE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeCollectAggregate(AstNode const* list, AstNode const* aggregations,
|
||||
AstNode const* options) {
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECT_AGGREGATE);
|
||||
|
||||
if (options == nullptr) {
|
||||
// no options given. now use default options
|
||||
options = &NopNode;
|
||||
}
|
||||
|
||||
node->addMember(options);
|
||||
node->addMember(list);
|
||||
node->addMember(aggregations);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST sort node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -314,6 +314,12 @@ class Ast {
|
|||
|
||||
AstNode* createNodeCollectCount(AstNode const*, char const*, size_t length,
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST collect node, AGGREGATE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeCollectAggregate(AstNode const*, AstNode const*, AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST sort node
|
||||
|
|
|
@ -158,7 +158,8 @@ std::unordered_map<int, std::string const> const AstNode::TypeNames{
|
|||
{static_cast<int>(NODE_TYPE_DIRECTION), "direction"},
|
||||
{static_cast<int>(NODE_TYPE_COLLECTION_LIST), "collection list"},
|
||||
{static_cast<int>(NODE_TYPE_OPERATOR_NARY_AND), "n-ary and"},
|
||||
{static_cast<int>(NODE_TYPE_OPERATOR_NARY_OR), "n-ary or"}};
|
||||
{static_cast<int>(NODE_TYPE_OPERATOR_NARY_OR), "n-ary or"},
|
||||
{static_cast<int>(NODE_TYPE_COLLECT_AGGREGATE), "collect aggregate"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief names for AST node value types
|
||||
|
@ -572,6 +573,7 @@ AstNode::AstNode(Ast* ast, triagens::basics::Json const& json)
|
|||
case NODE_TYPE_COLLECT:
|
||||
case NODE_TYPE_COLLECT_COUNT:
|
||||
case NODE_TYPE_COLLECT_EXPRESSION:
|
||||
case NODE_TYPE_COLLECT_AGGREGATE:
|
||||
case NODE_TYPE_SORT:
|
||||
case NODE_TYPE_SORT_ELEMENT:
|
||||
case NODE_TYPE_LIMIT:
|
||||
|
@ -720,6 +722,7 @@ AstNode::AstNode(std::function<void(AstNode*)> registerNode,
|
|||
case NODE_TYPE_COLLECT:
|
||||
case NODE_TYPE_COLLECT_COUNT:
|
||||
case NODE_TYPE_COLLECT_EXPRESSION:
|
||||
case NODE_TYPE_COLLECT_AGGREGATE:
|
||||
case NODE_TYPE_SORT:
|
||||
case NODE_TYPE_SORT_ELEMENT:
|
||||
case NODE_TYPE_LIMIT:
|
||||
|
@ -2435,6 +2438,7 @@ void AstNode::findVariableAccess(
|
|||
case NODE_TYPE_NOP:
|
||||
case NODE_TYPE_COLLECT_COUNT:
|
||||
case NODE_TYPE_COLLECT_EXPRESSION:
|
||||
case NODE_TYPE_COLLECT_AGGREGATE:
|
||||
case NODE_TYPE_CALCULATED_OBJECT_ELEMENT:
|
||||
case NODE_TYPE_UPSERT:
|
||||
case NODE_TYPE_EXAMPLE:
|
||||
|
@ -2576,6 +2580,7 @@ AstNode const* AstNode::findReference(AstNode const* findme) const {
|
|||
case NODE_TYPE_NOP:
|
||||
case NODE_TYPE_COLLECT_COUNT:
|
||||
case NODE_TYPE_COLLECT_EXPRESSION:
|
||||
case NODE_TYPE_COLLECT_AGGREGATE:
|
||||
case NODE_TYPE_CALCULATED_OBJECT_ELEMENT:
|
||||
case NODE_TYPE_UPSERT:
|
||||
case NODE_TYPE_EXAMPLE:
|
||||
|
|
|
@ -189,7 +189,8 @@ enum AstNodeType : uint32_t {
|
|||
NODE_TYPE_COLLECTION_LIST = 60,
|
||||
NODE_TYPE_DIRECTION = 61,
|
||||
NODE_TYPE_OPERATOR_NARY_AND = 62,
|
||||
NODE_TYPE_OPERATOR_NARY_OR = 63
|
||||
NODE_TYPE_OPERATOR_NARY_OR = 63,
|
||||
NODE_TYPE_COLLECT_AGGREGATE = 64
|
||||
};
|
||||
|
||||
static_assert(NODE_TYPE_VALUE < NODE_TYPE_ARRAY, "incorrect node types order");
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/// @author Max Neunhoeffer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/AggregateBlock.h"
|
||||
#include "Aql/CollectBlock.h"
|
||||
#include "Aql/AqlItemBlock.h"
|
||||
#include "Aql/ExecutionEngine.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
|
@ -36,14 +36,14 @@ using JsonHelper = triagens::basics::JsonHelper;
|
|||
using StringBuffer = triagens::basics::StringBuffer;
|
||||
|
||||
|
||||
AggregatorGroup::AggregatorGroup(bool count)
|
||||
CollectGroup::CollectGroup(bool count)
|
||||
: firstRow(0),
|
||||
lastRow(0),
|
||||
groupLength(0),
|
||||
rowsAreValid(false),
|
||||
count(count) {}
|
||||
|
||||
AggregatorGroup::~AggregatorGroup() {
|
||||
CollectGroup::~CollectGroup() {
|
||||
// reset();
|
||||
for (auto& it : groupBlocks) {
|
||||
delete it;
|
||||
|
@ -54,7 +54,7 @@ AggregatorGroup::~AggregatorGroup() {
|
|||
}
|
||||
|
||||
|
||||
void AggregatorGroup::initialize(size_t capacity) {
|
||||
void CollectGroup::initialize(size_t capacity) {
|
||||
// TRI_ASSERT(capacity > 0);
|
||||
|
||||
groupValues.clear();
|
||||
|
@ -73,7 +73,7 @@ void AggregatorGroup::initialize(size_t capacity) {
|
|||
groupLength = 0;
|
||||
}
|
||||
|
||||
void AggregatorGroup::reset() {
|
||||
void CollectGroup::reset() {
|
||||
for (auto& it : groupBlocks) {
|
||||
delete it;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ void AggregatorGroup::reset() {
|
|||
groupLength = 0;
|
||||
}
|
||||
|
||||
void AggregatorGroup::addValues(AqlItemBlock const* src,
|
||||
void CollectGroup::addValues(AqlItemBlock const* src,
|
||||
RegisterId groupRegister) {
|
||||
if (groupRegister == ExecutionNode::MaxRegisterId) {
|
||||
// nothing to do
|
||||
|
@ -107,7 +107,7 @@ void AggregatorGroup::addValues(AqlItemBlock const* src,
|
|||
} else {
|
||||
auto block = src->slice(firstRow, lastRow + 1);
|
||||
try {
|
||||
TRI_IF_FAILURE("AggregatorGroup::addValues") {
|
||||
TRI_IF_FAILURE("CollectGroup::addValues") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
groupBlocks.emplace_back(block);
|
||||
|
@ -124,15 +124,15 @@ void AggregatorGroup::addValues(AqlItemBlock const* src,
|
|||
}
|
||||
|
||||
|
||||
SortedAggregateBlock::SortedAggregateBlock(ExecutionEngine* engine,
|
||||
AggregateNode const* en)
|
||||
SortedCollectBlock::SortedCollectBlock(ExecutionEngine* engine,
|
||||
CollectNode const* en)
|
||||
: ExecutionBlock(engine, en),
|
||||
_aggregateRegisters(),
|
||||
_currentGroup(en->_count),
|
||||
_expressionRegister(ExecutionNode::MaxRegisterId),
|
||||
_groupRegister(ExecutionNode::MaxRegisterId),
|
||||
_variableNames() {
|
||||
for (auto const& p : en->_aggregateVariables) {
|
||||
for (auto const& p : en->_collectVariables) {
|
||||
// We know that planRegisters() has been run, so
|
||||
// getPlanNode()->_registerPlan is set up
|
||||
auto itOut = en->getRegisterPlan()->varInfo.find(p.first->id);
|
||||
|
@ -177,7 +177,7 @@ SortedAggregateBlock::SortedAggregateBlock(ExecutionEngine* engine,
|
|||
// (which means no FOR in which we are contained)
|
||||
|
||||
if (usedVariableIds.find(vi.first) == usedVariableIds.end()) {
|
||||
// variable is not visible to the AggregateBlock
|
||||
// variable is not visible to the CollectBlock
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -201,13 +201,13 @@ SortedAggregateBlock::SortedAggregateBlock(ExecutionEngine* engine,
|
|||
}
|
||||
}
|
||||
|
||||
SortedAggregateBlock::~SortedAggregateBlock() {}
|
||||
SortedCollectBlock::~SortedCollectBlock() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialize
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SortedAggregateBlock::initialize() {
|
||||
int SortedCollectBlock::initialize() {
|
||||
int res = ExecutionBlock::initialize();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -220,7 +220,7 @@ int SortedAggregateBlock::initialize() {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
int SortedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||
int SortedCollectBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||
bool skipping, AqlItemBlock*& result,
|
||||
size_t& skipped) {
|
||||
TRI_ASSERT(result == nullptr && skipped == 0);
|
||||
|
@ -337,7 +337,7 @@ int SortedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
|
||||
if (!hasMore) {
|
||||
try {
|
||||
TRI_IF_FAILURE("SortedAggregateBlock::hasMore") {
|
||||
TRI_IF_FAILURE("SortedCollectBlock::hasMore") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
hasMore = ExecutionBlock::getBlock(atLeast, atMost);
|
||||
|
@ -353,7 +353,7 @@ int SortedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
try {
|
||||
// emit last buffered group
|
||||
if (!skipping) {
|
||||
TRI_IF_FAILURE("SortedAggregateBlock::getOrSkipSome") {
|
||||
TRI_IF_FAILURE("SortedCollectBlock::getOrSkipSome") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ int SortedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
/// @brief writes the current group data into the result
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SortedAggregateBlock::emitGroup(AqlItemBlock const* cur, AqlItemBlock* res,
|
||||
void SortedCollectBlock::emitGroup(AqlItemBlock const* cur, AqlItemBlock* res,
|
||||
size_t row) {
|
||||
if (row > 0) {
|
||||
// re-use already copied aqlvalues
|
||||
|
@ -433,12 +433,12 @@ void SortedAggregateBlock::emitGroup(AqlItemBlock const* cur, AqlItemBlock* res,
|
|||
// set the group values
|
||||
_currentGroup.addValues(cur, _groupRegister);
|
||||
|
||||
if (static_cast<AggregateNode const*>(_exeNode)->_count) {
|
||||
if (static_cast<CollectNode const*>(_exeNode)->_count) {
|
||||
// only set group count in result register
|
||||
res->setValue(
|
||||
row, _groupRegister,
|
||||
AqlValue(new Json(static_cast<double>(_currentGroup.groupLength))));
|
||||
} else if (static_cast<AggregateNode const*>(_exeNode)
|
||||
} else if (static_cast<CollectNode const*>(_exeNode)
|
||||
->_expressionVariable != nullptr) {
|
||||
// copy expression result into result register
|
||||
res->setValue(row, _groupRegister,
|
||||
|
@ -457,12 +457,12 @@ void SortedAggregateBlock::emitGroup(AqlItemBlock const* cur, AqlItemBlock* res,
|
|||
}
|
||||
|
||||
|
||||
HashedAggregateBlock::HashedAggregateBlock(ExecutionEngine* engine,
|
||||
AggregateNode const* en)
|
||||
HashedCollectBlock::HashedCollectBlock(ExecutionEngine* engine,
|
||||
CollectNode const* en)
|
||||
: ExecutionBlock(engine, en),
|
||||
_aggregateRegisters(),
|
||||
_groupRegister(ExecutionNode::MaxRegisterId) {
|
||||
for (auto const& p : en->_aggregateVariables) {
|
||||
for (auto const& p : en->_collectVariables) {
|
||||
// We know that planRegisters() has been run, so
|
||||
// getPlanNode()->_registerPlan is set up
|
||||
auto itOut = en->getRegisterPlan()->varInfo.find(p.first->id);
|
||||
|
@ -477,7 +477,7 @@ HashedAggregateBlock::HashedAggregateBlock(ExecutionEngine* engine,
|
|||
}
|
||||
|
||||
if (en->_outVariable != nullptr) {
|
||||
TRI_ASSERT(static_cast<AggregateNode const*>(_exeNode)->_count);
|
||||
TRI_ASSERT(static_cast<CollectNode const*>(_exeNode)->_count);
|
||||
|
||||
auto const& registerPlan = en->getRegisterPlan()->varInfo;
|
||||
auto it = registerPlan.find(en->_outVariable->id);
|
||||
|
@ -486,19 +486,19 @@ HashedAggregateBlock::HashedAggregateBlock(ExecutionEngine* engine,
|
|||
TRI_ASSERT(_groupRegister > 0 &&
|
||||
_groupRegister < ExecutionNode::MaxRegisterId);
|
||||
} else {
|
||||
TRI_ASSERT(!static_cast<AggregateNode const*>(_exeNode)->_count);
|
||||
TRI_ASSERT(!static_cast<CollectNode const*>(_exeNode)->_count);
|
||||
}
|
||||
|
||||
TRI_ASSERT(!_aggregateRegisters.empty());
|
||||
}
|
||||
|
||||
HashedAggregateBlock::~HashedAggregateBlock() {}
|
||||
HashedCollectBlock::~HashedCollectBlock() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialize
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int HashedAggregateBlock::initialize() {
|
||||
int HashedCollectBlock::initialize() {
|
||||
int res = ExecutionBlock::initialize();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -508,7 +508,7 @@ int HashedAggregateBlock::initialize() {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
int HashedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||
int HashedCollectBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||
bool skipping, AqlItemBlock*& result,
|
||||
size_t& skipped) {
|
||||
TRI_ASSERT(result == nullptr && skipped == 0);
|
||||
|
@ -539,7 +539,7 @@ int HashedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
allGroups(1024, GroupKeyHash(_trx, colls), GroupKeyEqual(_trx, colls));
|
||||
|
||||
auto buildResult = [&](AqlItemBlock const* src) {
|
||||
auto planNode = static_cast<AggregateNode const*>(getPlanNode());
|
||||
auto planNode = static_cast<CollectNode const*>(getPlanNode());
|
||||
auto nrRegs = planNode->getRegisterPlan()->nrRegs[planNode->getDepth()];
|
||||
|
||||
auto result = std::make_unique<AqlItemBlock>(allGroups.size(), nrRegs);
|
||||
|
@ -635,7 +635,7 @@ int HashedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
try {
|
||||
// emit last buffered group
|
||||
if (!skipping) {
|
||||
TRI_IF_FAILURE("HashedAggregateBlock::getOrSkipSome") {
|
||||
TRI_IF_FAILURE("HashedCollectBlock::getOrSkipSome") {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
}
|
||||
|
@ -689,7 +689,7 @@ int HashedAggregateBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
|||
/// @brief hasher for groups
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t HashedAggregateBlock::GroupKeyHash::operator()(
|
||||
size_t HashedCollectBlock::GroupKeyHash::operator()(
|
||||
std::vector<AqlValue> const& value) const {
|
||||
uint64_t hash = 0x12345678;
|
||||
|
||||
|
@ -704,7 +704,7 @@ size_t HashedAggregateBlock::GroupKeyHash::operator()(
|
|||
/// @brief comparator for groups
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HashedAggregateBlock::GroupKeyEqual::operator()(
|
||||
bool HashedCollectBlock::GroupKeyEqual::operator()(
|
||||
std::vector<AqlValue> const& lhs, std::vector<AqlValue> const& rhs) const {
|
||||
size_t const n = lhs.size();
|
||||
|
|
@ -21,11 +21,11 @@
|
|||
/// @author Jan Steemann
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_AQL_AGGREGATE_BLOCK_H
|
||||
#define ARANGOD_AQL_AGGREGATE_BLOCK_H 1
|
||||
#ifndef ARANGOD_AQL_COLLECT_BLOCK_H
|
||||
#define ARANGOD_AQL_COLLECT_BLOCK_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/CollectNode.h"
|
||||
#include "Aql/ExecutionBlock.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
|
||||
|
@ -43,7 +43,7 @@ class ExecutionEngine;
|
|||
/// @brief details about the current group
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AggregatorGroup {
|
||||
struct CollectGroup {
|
||||
std::vector<AqlValue> groupValues;
|
||||
std::vector<TRI_document_collection_t const*> collections;
|
||||
|
||||
|
@ -54,11 +54,11 @@ struct AggregatorGroup {
|
|||
bool rowsAreValid;
|
||||
bool const count;
|
||||
|
||||
AggregatorGroup() = delete;
|
||||
CollectGroup() = delete;
|
||||
|
||||
explicit AggregatorGroup(bool);
|
||||
explicit CollectGroup(bool);
|
||||
|
||||
~AggregatorGroup();
|
||||
~CollectGroup();
|
||||
|
||||
void initialize(size_t capacity);
|
||||
void reset();
|
||||
|
@ -77,11 +77,11 @@ struct AggregatorGroup {
|
|||
};
|
||||
|
||||
|
||||
class SortedAggregateBlock : public ExecutionBlock {
|
||||
class SortedCollectBlock : public ExecutionBlock {
|
||||
public:
|
||||
SortedAggregateBlock(ExecutionEngine*, AggregateNode const*);
|
||||
SortedCollectBlock(ExecutionEngine*, CollectNode const*);
|
||||
|
||||
~SortedAggregateBlock();
|
||||
~SortedCollectBlock();
|
||||
|
||||
int initialize() override;
|
||||
|
||||
|
@ -106,7 +106,7 @@ class SortedAggregateBlock : public ExecutionBlock {
|
|||
/// @brief details about the current group
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregatorGroup _currentGroup;
|
||||
CollectGroup _currentGroup;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the optional register that contains the input expression values for
|
||||
|
@ -132,11 +132,11 @@ class SortedAggregateBlock : public ExecutionBlock {
|
|||
};
|
||||
|
||||
|
||||
class HashedAggregateBlock : public ExecutionBlock {
|
||||
class HashedCollectBlock : public ExecutionBlock {
|
||||
public:
|
||||
HashedAggregateBlock(ExecutionEngine*, AggregateNode const*);
|
||||
HashedCollectBlock(ExecutionEngine*, CollectNode const*);
|
||||
|
||||
~HashedAggregateBlock();
|
||||
~HashedCollectBlock();
|
||||
|
||||
int initialize() override;
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
/// @author Jan Steemann
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "AggregateNode.h"
|
||||
#include "CollectNode.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/ExecutionPlan.h"
|
||||
#include "Aql/WalkerWorker.h"
|
||||
|
@ -31,17 +31,17 @@ using namespace triagens::basics;
|
|||
using namespace triagens::aql;
|
||||
|
||||
|
||||
AggregateNode::AggregateNode(
|
||||
CollectNode::CollectNode(
|
||||
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,
|
||||
collectVariables,
|
||||
bool count, bool isDistinctCommand)
|
||||
: ExecutionNode(plan, base),
|
||||
_options(base),
|
||||
_aggregateVariables(aggregateVariables),
|
||||
_collectVariables(collectVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
|
@ -51,10 +51,10 @@ AggregateNode::AggregateNode(
|
|||
_specialized(false) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toJson, for AggregateNode
|
||||
/// @brief toJson, for CollectNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::toJsonHelper(triagens::basics::Json& nodes,
|
||||
void CollectNode::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
|
||||
|
@ -64,9 +64,9 @@ void AggregateNode::toJsonHelper(triagens::basics::Json& nodes,
|
|||
}
|
||||
|
||||
triagens::basics::Json values(triagens::basics::Json::Array,
|
||||
_aggregateVariables.size());
|
||||
_collectVariables.size());
|
||||
|
||||
for (auto it = _aggregateVariables.begin(); it != _aggregateVariables.end();
|
||||
for (auto it = _collectVariables.begin(); it != _collectVariables.end();
|
||||
++it) {
|
||||
triagens::basics::Json variable(triagens::basics::Json::Object);
|
||||
variable("outVariable", (*it).first->toJson())("inVariable",
|
||||
|
@ -110,11 +110,11 @@ void AggregateNode::toJsonHelper(triagens::basics::Json& nodes,
|
|||
/// @brief clone ExecutionNode recursively
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* AggregateNode::clone(ExecutionPlan* plan, bool withDependencies,
|
||||
ExecutionNode* CollectNode::clone(ExecutionPlan* plan, bool withDependencies,
|
||||
bool withProperties) const {
|
||||
auto outVariable = _outVariable;
|
||||
auto expressionVariable = _expressionVariable;
|
||||
auto aggregateVariables = _aggregateVariables;
|
||||
auto collectVariables = _collectVariables;
|
||||
|
||||
if (withProperties) {
|
||||
if (expressionVariable != nullptr) {
|
||||
|
@ -127,16 +127,16 @@ ExecutionNode* AggregateNode::clone(ExecutionPlan* plan, bool withDependencies,
|
|||
}
|
||||
|
||||
// need to re-create all variables
|
||||
aggregateVariables.clear();
|
||||
collectVariables.clear();
|
||||
|
||||
for (auto& it : _aggregateVariables) {
|
||||
for (auto& it : _collectVariables) {
|
||||
auto out = plan->getAst()->variables()->createVariable(it.first);
|
||||
auto in = plan->getAst()->variables()->createVariable(it.second);
|
||||
aggregateVariables.emplace_back(std::make_pair(out, in));
|
||||
collectVariables.emplace_back(std::make_pair(out, in));
|
||||
}
|
||||
}
|
||||
|
||||
auto c = new AggregateNode(plan, _id, _options, aggregateVariables,
|
||||
auto c = new CollectNode(plan, _id, _options, collectVariables,
|
||||
expressionVariable, outVariable, _keepVariables,
|
||||
_variableMap, _count, _isDistinctCommand);
|
||||
|
||||
|
@ -174,7 +174,7 @@ struct UserVarFinder final : public WalkerWorker<ExecutionNode> {
|
|||
en->getType() == ExecutionNode::INDEX ||
|
||||
en->getType() == ExecutionNode::ENUMERATE_LIST ||
|
||||
en->getType() == ExecutionNode::TRAVERSAL ||
|
||||
en->getType() == ExecutionNode::AGGREGATE) {
|
||||
en->getType() == ExecutionNode::COLLECT) {
|
||||
depth += 1;
|
||||
}
|
||||
// Now depth is set correct for this node.
|
||||
|
@ -193,7 +193,7 @@ struct UserVarFinder final : public WalkerWorker<ExecutionNode> {
|
|||
/// @brief getVariablesUsedHere, returning a vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Variable const*> AggregateNode::getVariablesUsedHere() const {
|
||||
std::vector<Variable const*> CollectNode::getVariablesUsedHere() const {
|
||||
std::unordered_set<Variable const*> v;
|
||||
// actual work is done by that method
|
||||
getVariablesUsedHere(v);
|
||||
|
@ -211,9 +211,9 @@ std::vector<Variable const*> AggregateNode::getVariablesUsedHere() const {
|
|||
/// @brief getVariablesUsedHere, modifying the set in-place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregateNode::getVariablesUsedHere(
|
||||
void CollectNode::getVariablesUsedHere(
|
||||
std::unordered_set<Variable const*>& vars) const {
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
for (auto const& p : _collectVariables) {
|
||||
vars.emplace(p.second);
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ void AggregateNode::getVariablesUsedHere(
|
|||
// Here we have to find all user defined variables in this query
|
||||
// amongst our dependencies:
|
||||
UserVarFinder finder(1);
|
||||
auto myselfAsNonConst = const_cast<AggregateNode*>(this);
|
||||
auto myselfAsNonConst = const_cast<CollectNode*>(this);
|
||||
myselfAsNonConst->walk(&finder);
|
||||
if (finder.depth == 1) {
|
||||
// we are top level, let's run again with mindepth = 0
|
||||
|
@ -251,7 +251,7 @@ void AggregateNode::getVariablesUsedHere(
|
|||
/// @brief estimateCost
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double AggregateNode::estimateCost(size_t& nrItems) const {
|
||||
double CollectNode::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
|
||||
|
@ -259,10 +259,10 @@ double AggregateNode::estimateCost(size_t& nrItems) const {
|
|||
// 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
|
||||
// Nevertheless, the optimizer does not do much with CollectNodes
|
||||
// and thus this potential overestimation does not really matter.
|
||||
|
||||
if (_count && _aggregateVariables.empty()) {
|
||||
if (_count && _collectVariables.empty()) {
|
||||
// we are known to only produce a single output row
|
||||
nrItems = 1;
|
||||
} else {
|
|
@ -21,11 +21,11 @@
|
|||
/// @author Jan Steemann
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_AQL_AGGREGATE_NODE_H
|
||||
#define ARANGOD_AQL_AGGREGATE_NODE_H 1
|
||||
#ifndef ARANGOD_AQL_COLLECT_NODE_H
|
||||
#define ARANGOD_AQL_COLLECT_NODE_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/types.h"
|
||||
#include "Aql/Variable.h"
|
||||
|
@ -41,15 +41,15 @@ class RedundantCalculationsReplacer;
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief class AggregateNode
|
||||
/// @brief class CollectNode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AggregateNode : public ExecutionNode {
|
||||
class CollectNode : public ExecutionNode {
|
||||
friend class ExecutionNode;
|
||||
friend class ExecutionBlock;
|
||||
friend class SortedAggregateBlock;
|
||||
friend class HashedAggregateBlock;
|
||||
friend class HashedCollectBlock;
|
||||
friend class RedundantCalculationsReplacer;
|
||||
friend class SortedCollectBlock;
|
||||
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,17 +57,17 @@ class AggregateNode : public ExecutionNode {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public:
|
||||
AggregateNode(
|
||||
ExecutionPlan* plan, size_t id, AggregationOptions const& options,
|
||||
CollectNode(
|
||||
ExecutionPlan* plan, size_t id, CollectOptions const& options,
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const&
|
||||
aggregateVariables,
|
||||
collectVariables,
|
||||
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),
|
||||
_collectVariables(collectVariables),
|
||||
_expressionVariable(expressionVariable),
|
||||
_outVariable(outVariable),
|
||||
_keepVariables(keepVariables),
|
||||
|
@ -79,20 +79,20 @@ class AggregateNode : public ExecutionNode {
|
|||
TRI_ASSERT(!_count || _outVariable != nullptr);
|
||||
}
|
||||
|
||||
AggregateNode(
|
||||
CollectNode(
|
||||
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,
|
||||
collectVariables,
|
||||
bool count, bool isDistinctCommand);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the type of the node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NodeType getType() const override final { return AGGREGATE; }
|
||||
NodeType getType() const override final { return COLLECT; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node requires an additional post SORT
|
||||
|
@ -116,7 +116,7 @@ class AggregateNode : public ExecutionNode {
|
|||
/// @brief return the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions::AggregationMethod aggregationMethod() const {
|
||||
CollectOptions::CollectMethod aggregationMethod() const {
|
||||
return _options.method;
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ class AggregateNode : public ExecutionNode {
|
|||
/// @brief set the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void aggregationMethod(AggregationOptions::AggregationMethod method) {
|
||||
void aggregationMethod(CollectOptions::CollectMethod method) {
|
||||
_options.method = method;
|
||||
}
|
||||
|
||||
|
@ -132,13 +132,13 @@ class AggregateNode : public ExecutionNode {
|
|||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions const& getOptions() const { return _options; }
|
||||
CollectOptions const& getOptions() const { return _options; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions& getOptions() { return _options; }
|
||||
CollectOptions& getOptions() { return _options; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief export to JSON
|
||||
|
@ -219,8 +219,8 @@ class AggregateNode : public ExecutionNode {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const&
|
||||
aggregateVariables() const {
|
||||
return _aggregateVariables;
|
||||
collectVariables() const {
|
||||
return _collectVariables;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -243,10 +243,10 @@ class AggregateNode : public ExecutionNode {
|
|||
std::vector<Variable const*> getVariablesSetHere() const override final {
|
||||
std::vector<Variable const*> v;
|
||||
size_t const n =
|
||||
_aggregateVariables.size() + (_outVariable == nullptr ? 0 : 1);
|
||||
_collectVariables.size() + (_outVariable == nullptr ? 0 : 1);
|
||||
v.reserve(n);
|
||||
|
||||
for (auto const& p : _aggregateVariables) {
|
||||
for (auto const& p : _collectVariables) {
|
||||
v.emplace_back(p.first);
|
||||
}
|
||||
if (_outVariable != nullptr) {
|
||||
|
@ -261,13 +261,13 @@ class AggregateNode : public ExecutionNode {
|
|||
/// @brief options for the aggregation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions _options;
|
||||
CollectOptions _options;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input/output variables for the aggregation (out, in)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
|
||||
std::vector<std::pair<Variable const*, Variable const*>> _collectVariables;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief input expression variable (might be null)
|
|
@ -21,7 +21,7 @@
|
|||
/// @author Max Neunhoeffer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
|
||||
using namespace triagens::aql;
|
||||
|
@ -32,7 +32,7 @@ using JsonHelper = triagens::basics::JsonHelper;
|
|||
/// @brief constructor, using JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions::AggregationOptions(Json const& json) {
|
||||
CollectOptions::CollectOptions(Json const& json) {
|
||||
Json obj = json.get("aggregationOptions");
|
||||
|
||||
method =
|
||||
|
@ -43,8 +43,8 @@ AggregationOptions::AggregationOptions(Json const& json) {
|
|||
/// @brief whether or not the hash method can be used
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AggregationOptions::canUseHashMethod() const {
|
||||
if (method == AggregationMethod::AGGREGATION_METHOD_SORTED) {
|
||||
bool CollectOptions::canUseHashMethod() const {
|
||||
if (method == CollectMethod::COLLECT_METHOD_SORTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ bool AggregationOptions::canUseHashMethod() const {
|
|||
/// @brief convert the options to JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AggregationOptions::toJson(triagens::basics::Json& json,
|
||||
void CollectOptions::toJson(triagens::basics::Json& json,
|
||||
TRI_memory_zone_t* zone) const {
|
||||
Json options;
|
||||
|
||||
|
@ -68,28 +68,28 @@ void AggregationOptions::toJson(triagens::basics::Json& json,
|
|||
/// @brief get the aggregation method from a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions::AggregationMethod AggregationOptions::methodFromString(
|
||||
CollectOptions::CollectMethod CollectOptions::methodFromString(
|
||||
std::string const& method) {
|
||||
if (method == "hash") {
|
||||
return AggregationMethod::AGGREGATION_METHOD_HASH;
|
||||
return CollectMethod::COLLECT_METHOD_HASH;
|
||||
}
|
||||
if (method == "sorted") {
|
||||
return AggregationMethod::AGGREGATION_METHOD_SORTED;
|
||||
return CollectMethod::COLLECT_METHOD_SORTED;
|
||||
}
|
||||
|
||||
return AggregationMethod::AGGREGATION_METHOD_UNDEFINED;
|
||||
return CollectMethod::COLLECT_METHOD_UNDEFINED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stringify the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string AggregationOptions::methodToString(
|
||||
AggregationOptions::AggregationMethod method) {
|
||||
if (method == AggregationMethod::AGGREGATION_METHOD_HASH) {
|
||||
std::string CollectOptions::methodToString(
|
||||
CollectOptions::CollectMethod method) {
|
||||
if (method == CollectMethod::COLLECT_METHOD_HASH) {
|
||||
return std::string("hash");
|
||||
}
|
||||
if (method == AggregationMethod::AGGREGATION_METHOD_SORTED) {
|
||||
if (method == CollectMethod::COLLECT_METHOD_SORTED) {
|
||||
return std::string("sorted");
|
||||
}
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
/// @author Max Neunhoeffer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGOD_AQL_AGGREGATION_OPTIONS_H
|
||||
#define ARANGOD_AQL_AGGREGATION_OPTIONS_H 1
|
||||
#ifndef ARANGOD_AQL_COLLECT_OPTIONS_H
|
||||
#define ARANGOD_AQL_COLLECT_OPTIONS_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
|
@ -31,19 +31,19 @@ namespace triagens {
|
|||
namespace aql {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief AggregationOptions
|
||||
/// @brief CollectOptions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AggregationOptions {
|
||||
struct CollectOptions {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief selected aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum AggregationMethod {
|
||||
AGGREGATION_METHOD_UNDEFINED,
|
||||
AGGREGATION_METHOD_HASH,
|
||||
AGGREGATION_METHOD_SORTED
|
||||
enum CollectMethod {
|
||||
COLLECT_METHOD_UNDEFINED,
|
||||
COLLECT_METHOD_HASH,
|
||||
COLLECT_METHOD_SORTED
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,13 +51,13 @@ struct AggregationOptions {
|
|||
/// @brief constructor, using default values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions() : method(AGGREGATION_METHOD_UNDEFINED) {}
|
||||
CollectOptions() : method(COLLECT_METHOD_UNDEFINED) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor, using JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions(triagens::basics::Json const&);
|
||||
CollectOptions(triagens::basics::Json const&);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -76,17 +76,17 @@ struct AggregationOptions {
|
|||
/// @brief get the aggregation method from a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AggregationMethod methodFromString(std::string const&);
|
||||
static CollectMethod methodFromString(std::string const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stringify the aggregation method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::string methodToString(
|
||||
AggregationOptions::AggregationMethod method);
|
||||
CollectOptions::CollectMethod method);
|
||||
|
||||
|
||||
AggregationMethod method;
|
||||
CollectMethod method;
|
||||
};
|
||||
|
||||
} // namespace triagens::aql
|
|
@ -33,7 +33,7 @@ using EN = triagens::aql::ExecutionNode;
|
|||
bool ConditionFinder::before(ExecutionNode* en) {
|
||||
switch (en->getType()) {
|
||||
case EN::ENUMERATE_LIST:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::SCATTER:
|
||||
case EN::DISTRIBUTE:
|
||||
case EN::GATHER:
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/ExecutionEngine.h"
|
||||
#include "Aql/AggregateBlock.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Aql/BasicBlocks.h"
|
||||
#include "Aql/CalculationBlock.h"
|
||||
#include "Aql/ClusterBlocks.h"
|
||||
#include "Aql/CollectBlock.h"
|
||||
#include "Aql/CollectNode.h"
|
||||
#include "Aql/EnumerateCollectionBlock.h"
|
||||
#include "Aql/EnumerateListBlock.h"
|
||||
#include "Aql/ExecutionBlock.h"
|
||||
|
@ -87,22 +87,22 @@ static ExecutionBlock* CreateBlock(
|
|||
case ExecutionNode::SORT: {
|
||||
return new SortBlock(engine, static_cast<SortNode const*>(en));
|
||||
}
|
||||
case ExecutionNode::AGGREGATE: {
|
||||
case ExecutionNode::COLLECT: {
|
||||
auto aggregationMethod =
|
||||
static_cast<AggregateNode const*>(en)->aggregationMethod();
|
||||
static_cast<CollectNode const*>(en)->aggregationMethod();
|
||||
|
||||
if (aggregationMethod ==
|
||||
AggregationOptions::AggregationMethod::AGGREGATION_METHOD_HASH) {
|
||||
return new HashedAggregateBlock(engine,
|
||||
static_cast<AggregateNode const*>(en));
|
||||
} else if (aggregationMethod == AggregationOptions::AggregationMethod::
|
||||
AGGREGATION_METHOD_SORTED) {
|
||||
return new SortedAggregateBlock(engine,
|
||||
static_cast<AggregateNode const*>(en));
|
||||
CollectOptions::CollectMethod::COLLECT_METHOD_HASH) {
|
||||
return new HashedCollectBlock(engine,
|
||||
static_cast<CollectNode const*>(en));
|
||||
} else if (aggregationMethod == CollectOptions::CollectMethod::
|
||||
COLLECT_METHOD_SORTED) {
|
||||
return new SortedCollectBlock(engine,
|
||||
static_cast<CollectNode const*>(en));
|
||||
}
|
||||
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"cannot instantiate AggregateBlock with "
|
||||
"cannot instantiate CollectBlock with "
|
||||
"undetermined aggregation method");
|
||||
}
|
||||
case ExecutionNode::SUBQUERY: {
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ExecutionNode.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/ClusterNodes.h"
|
||||
#include "Aql/Collection.h"
|
||||
#include "Aql/CollectNode.h"
|
||||
#include "Aql/ExecutionPlan.h"
|
||||
#include "Aql/IndexNode.h"
|
||||
#include "Aql/ModificationNodes.h"
|
||||
|
@ -64,7 +64,7 @@ std::unordered_map<int, std::string const> const ExecutionNode::TypeNames{
|
|||
{static_cast<int>(SUBQUERY), "SubqueryNode"},
|
||||
{static_cast<int>(FILTER), "FilterNode"},
|
||||
{static_cast<int>(SORT), "SortNode"},
|
||||
{static_cast<int>(AGGREGATE), "AggregateNode"},
|
||||
{static_cast<int>(COLLECT), "CollectNode"},
|
||||
{static_cast<int>(RETURN), "ReturnNode"},
|
||||
{static_cast<int>(REMOVE), "RemoveNode"},
|
||||
{static_cast<int>(INSERT), "InsertNode"},
|
||||
|
@ -159,7 +159,7 @@ ExecutionNode* ExecutionNode::fromJsonFactory(
|
|||
getSortElements(elements, plan, oneNode, "SortNode");
|
||||
return new SortNode(plan, oneNode, elements, stable);
|
||||
}
|
||||
case AGGREGATE: {
|
||||
case COLLECT: {
|
||||
Variable* expressionVariable =
|
||||
varFromJson(plan->getAst(), oneNode, "expressionVariable", Optional);
|
||||
Variable* outVariable =
|
||||
|
@ -186,9 +186,9 @@ ExecutionNode* ExecutionNode::fromJsonFactory(
|
|||
|
||||
size_t const len = jsonAggregates.size();
|
||||
std::vector<std::pair<Variable const*, Variable const*>>
|
||||
aggregateVariables;
|
||||
collectVariables;
|
||||
|
||||
aggregateVariables.reserve(len);
|
||||
collectVariables.reserve(len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
triagens::basics::Json oneJsonAggregate =
|
||||
jsonAggregates.at(static_cast<int>(i));
|
||||
|
@ -197,16 +197,16 @@ ExecutionNode* ExecutionNode::fromJsonFactory(
|
|||
Variable* inVar =
|
||||
varFromJson(plan->getAst(), oneJsonAggregate, "inVariable");
|
||||
|
||||
aggregateVariables.emplace_back(std::make_pair(outVar, inVar));
|
||||
collectVariables.emplace_back(std::make_pair(outVar, inVar));
|
||||
}
|
||||
|
||||
bool count = JsonHelper::checkAndGetBooleanValue(oneNode.json(), "count");
|
||||
bool isDistinctCommand = JsonHelper::checkAndGetBooleanValue(
|
||||
oneNode.json(), "isDistinctCommand");
|
||||
|
||||
auto node = new AggregateNode(
|
||||
auto node = new CollectNode(
|
||||
plan, oneNode, expressionVariable, outVariable, keepVariables,
|
||||
plan->getAst()->variables()->variables(false), aggregateVariables,
|
||||
plan->getAst()->variables()->variables(false), collectVariables,
|
||||
count, isDistinctCommand);
|
||||
|
||||
// specialize the node if required
|
||||
|
@ -924,7 +924,7 @@ void ExecutionNode::RegisterPlan::after(ExecutionNode* en) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ExecutionNode::AGGREGATE: {
|
||||
case ExecutionNode::COLLECT: {
|
||||
depth++;
|
||||
nrRegsHere.emplace_back(0);
|
||||
// create a copy of the last value here
|
||||
|
@ -933,8 +933,8 @@ void ExecutionNode::RegisterPlan::after(ExecutionNode* en) {
|
|||
RegisterId registerId = nrRegs.back();
|
||||
nrRegs.emplace_back(registerId);
|
||||
|
||||
auto ep = static_cast<AggregateNode const*>(en);
|
||||
for (auto const& p : ep->_aggregateVariables) {
|
||||
auto ep = static_cast<CollectNode const*>(en);
|
||||
for (auto const& p : ep->_collectVariables) {
|
||||
// p is std::pair<Variable const*,Variable const*>
|
||||
// and the first is the to be assigned output variable
|
||||
// for which we need to create a register in the current
|
||||
|
|
|
@ -75,7 +75,7 @@ class ExecutionNode {
|
|||
CALCULATION = 7,
|
||||
SUBQUERY = 8,
|
||||
SORT = 9,
|
||||
AGGREGATE = 10,
|
||||
COLLECT = 10,
|
||||
SCATTER = 11,
|
||||
GATHER = 12,
|
||||
REMOTE = 13,
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ExecutionPlan.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Aql/Ast.h"
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Aql/CollectNode.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/Expression.h"
|
||||
#include "Aql/ModificationNodes.h"
|
||||
|
@ -362,15 +362,15 @@ Variable const* ExecutionPlan::getOutVariable(ExecutionNode const* node) const {
|
|||
return static_cast<CalculationNode const*>(node)->outVariable();
|
||||
}
|
||||
|
||||
if (node->getType() == ExecutionNode::AGGREGATE) {
|
||||
// AggregateNode has an outVariale() method, but we cannot use it.
|
||||
// for AggregateNode, outVariable() will return the variable filled by INTO,
|
||||
if (node->getType() == ExecutionNode::COLLECT) {
|
||||
// CollectNode has an outVariale() method, but we cannot use it.
|
||||
// for CollectNode, outVariable() will return the variable filled by INTO,
|
||||
// but INTO is an optional feature
|
||||
// so this will return the first result variable of the COLLECT
|
||||
// this part of the code should only be called for anonymous COLLECT nodes,
|
||||
// which only have one result variable
|
||||
auto en = static_cast<AggregateNode const*>(node);
|
||||
auto const& vars = en->aggregateVariables();
|
||||
auto en = static_cast<CollectNode const*>(node);
|
||||
auto const& vars = en->collectVariables();
|
||||
|
||||
TRI_ASSERT(vars.size() == 1);
|
||||
auto v = vars[0].first;
|
||||
|
@ -386,17 +386,17 @@ Variable const* ExecutionPlan::getOutVariable(ExecutionNode const* node) const {
|
|||
/// @brief creates an anonymous COLLECT node (for a DISTINCT)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregateNode* ExecutionPlan::createAnonymousCollect(
|
||||
CollectNode* ExecutionPlan::createAnonymousCollect(
|
||||
CalculationNode const* previous) {
|
||||
// generate an out variable for the COLLECT
|
||||
auto out = _ast->variables()->createTemporaryVariable();
|
||||
TRI_ASSERT(out != nullptr);
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> const
|
||||
aggregateVariables{std::make_pair(out, previous->outVariable())};
|
||||
groupVariables{std::make_pair(out, previous->outVariable())};
|
||||
|
||||
auto en = new AggregateNode(this, nextId(), AggregationOptions(),
|
||||
aggregateVariables, nullptr, nullptr,
|
||||
auto en = new CollectNode(this, nextId(), CollectOptions(),
|
||||
groupVariables, nullptr, nullptr,
|
||||
std::vector<Variable const*>(),
|
||||
_ast->variables()->variables(false), false, true);
|
||||
|
||||
|
@ -479,9 +479,9 @@ ModificationOptions ExecutionPlan::createModificationOptions(
|
|||
/// @brief create COLLECT options from an AST node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions ExecutionPlan::createAggregationOptions(
|
||||
CollectOptions ExecutionPlan::createCollectOptions(
|
||||
AstNode const* node) {
|
||||
AggregationOptions options;
|
||||
CollectOptions options;
|
||||
|
||||
// parse the modification options we got
|
||||
if (node != nullptr && node->type == NODE_TYPE_OBJECT) {
|
||||
|
@ -499,7 +499,7 @@ AggregationOptions ExecutionPlan::createAggregationOptions(
|
|||
if (strcmp(name, "method") == 0) {
|
||||
if (value->isStringValue()) {
|
||||
options.method =
|
||||
AggregationOptions::methodFromString(value->getStringValue());
|
||||
CollectOptions::methodFromString(value->getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -874,13 +874,13 @@ ExecutionNode* ExecutionPlan::fromNodeCollect(ExecutionNode* previous,
|
|||
|
||||
TRI_ASSERT(n >= 2);
|
||||
|
||||
auto options = createAggregationOptions(node->getMember(0));
|
||||
auto options = createCollectOptions(node->getMember(0));
|
||||
|
||||
auto list = node->getMember(1);
|
||||
size_t const numVars = list->numMembers();
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables;
|
||||
aggregateVariables.reserve(numVars);
|
||||
std::vector<std::pair<Variable const*, Variable const*>> groupVariables;
|
||||
groupVariables.reserve(numVars);
|
||||
|
||||
for (size_t i = 0; i < numVars; ++i) {
|
||||
auto assigner = list->getMember(i);
|
||||
|
@ -900,12 +900,12 @@ ExecutionNode* ExecutionPlan::fromNodeCollect(ExecutionNode* previous,
|
|||
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||
// operand is a variable
|
||||
auto e = static_cast<Variable*>(expression->getData());
|
||||
aggregateVariables.emplace_back(std::make_pair(v, e));
|
||||
groupVariables.emplace_back(std::make_pair(v, e));
|
||||
} else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(expression, previous);
|
||||
previous = calc;
|
||||
aggregateVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
groupVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -933,8 +933,8 @@ ExecutionNode* ExecutionPlan::fromNodeCollect(ExecutionNode* previous,
|
|||
}
|
||||
}
|
||||
|
||||
auto collectNode = new AggregateNode(
|
||||
this, nextId(), options, aggregateVariables, nullptr, outVariable,
|
||||
auto collectNode = new CollectNode(
|
||||
this, nextId(), options, groupVariables, nullptr, outVariable,
|
||||
keepVariables, _ast->variables()->variables(false), false, false);
|
||||
|
||||
auto en = registerNode(collectNode);
|
||||
|
@ -951,13 +951,13 @@ ExecutionNode* ExecutionPlan::fromNodeCollectExpression(ExecutionNode* previous,
|
|||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_COLLECT_EXPRESSION);
|
||||
TRI_ASSERT(node->numMembers() == 4);
|
||||
|
||||
auto options = createAggregationOptions(node->getMember(0));
|
||||
auto options = createCollectOptions(node->getMember(0));
|
||||
|
||||
auto list = node->getMember(1);
|
||||
size_t const numVars = list->numMembers();
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables;
|
||||
aggregateVariables.reserve(numVars);
|
||||
std::vector<std::pair<Variable const*, Variable const*>> groupVariables;
|
||||
groupVariables.reserve(numVars);
|
||||
for (size_t i = 0; i < numVars; ++i) {
|
||||
auto assigner = list->getMember(i);
|
||||
|
||||
|
@ -976,12 +976,12 @@ ExecutionNode* ExecutionPlan::fromNodeCollectExpression(ExecutionNode* previous,
|
|||
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||
// operand is a variable
|
||||
auto e = static_cast<Variable*>(expression->getData());
|
||||
aggregateVariables.emplace_back(std::make_pair(v, e));
|
||||
groupVariables.emplace_back(std::make_pair(v, e));
|
||||
} else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(expression, previous);
|
||||
previous = calc;
|
||||
aggregateVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
groupVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,8 +1004,8 @@ ExecutionNode* ExecutionPlan::fromNodeCollectExpression(ExecutionNode* previous,
|
|||
auto v = node->getMember(2);
|
||||
Variable* outVariable = static_cast<Variable*>(v->getData());
|
||||
|
||||
auto collectNode = new AggregateNode(
|
||||
this, nextId(), options, aggregateVariables, expressionVariable,
|
||||
auto collectNode = new CollectNode(
|
||||
this, nextId(), options, groupVariables, expressionVariable,
|
||||
outVariable, std::vector<Variable const*>(),
|
||||
std::unordered_map<VariableId, std::string const>(), false, false);
|
||||
|
||||
|
@ -1025,13 +1025,13 @@ ExecutionNode* ExecutionPlan::fromNodeCollectCount(ExecutionNode* previous,
|
|||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_COLLECT_COUNT);
|
||||
TRI_ASSERT(node->numMembers() == 3);
|
||||
|
||||
auto options = createAggregationOptions(node->getMember(0));
|
||||
auto options = createCollectOptions(node->getMember(0));
|
||||
|
||||
auto list = node->getMember(1);
|
||||
size_t const numVars = list->numMembers();
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables;
|
||||
aggregateVariables.reserve(numVars);
|
||||
std::vector<std::pair<Variable const*, Variable const*>> groupVariables;
|
||||
groupVariables.reserve(numVars);
|
||||
for (size_t i = 0; i < numVars; ++i) {
|
||||
auto assigner = list->getMember(i);
|
||||
|
||||
|
@ -1050,12 +1050,12 @@ ExecutionNode* ExecutionPlan::fromNodeCollectCount(ExecutionNode* previous,
|
|||
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||
// operand is a variable
|
||||
auto e = static_cast<Variable*>(expression->getData());
|
||||
aggregateVariables.emplace_back(std::make_pair(v, e));
|
||||
groupVariables.emplace_back(std::make_pair(v, e));
|
||||
} else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(expression, previous);
|
||||
previous = calc;
|
||||
aggregateVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
groupVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1067,13 +1067,93 @@ ExecutionNode* ExecutionPlan::fromNodeCollectCount(ExecutionNode* previous,
|
|||
TRI_ASSERT(outVariable != nullptr);
|
||||
|
||||
auto en = registerNode(
|
||||
new AggregateNode(this, nextId(), options, aggregateVariables, nullptr,
|
||||
new CollectNode(this, nextId(), options, groupVariables, nullptr,
|
||||
outVariable, std::vector<Variable const*>(),
|
||||
_ast->variables()->variables(false), true, false));
|
||||
|
||||
return addDependency(previous, en);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an execution plan element from an AST COLLECT node, AGGREGATE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* ExecutionPlan::fromNodeCollectAggregate(ExecutionNode* previous,
|
||||
AstNode const* node) {
|
||||
TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_COLLECT_AGGREGATE);
|
||||
TRI_ASSERT(node->numMembers() == 3);
|
||||
|
||||
auto options = createCollectOptions(node->getMember(0));
|
||||
|
||||
// parse group variables
|
||||
auto list = node->getMember(1);
|
||||
size_t numVars = list->numMembers();
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> groupVariables;
|
||||
groupVariables.reserve(numVars);
|
||||
for (size_t i = 0; i < numVars; ++i) {
|
||||
auto assigner = list->getMember(i);
|
||||
|
||||
if (assigner == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_ASSERT(assigner->type == NODE_TYPE_ASSIGN);
|
||||
auto out = assigner->getMember(0);
|
||||
TRI_ASSERT(out != nullptr);
|
||||
auto v = static_cast<Variable*>(out->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
|
||||
auto expression = assigner->getMember(1);
|
||||
|
||||
if (expression->type == NODE_TYPE_REFERENCE) {
|
||||
// operand is a variable
|
||||
auto e = static_cast<Variable*>(expression->getData());
|
||||
groupVariables.emplace_back(std::make_pair(v, e));
|
||||
} else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(expression, previous);
|
||||
previous = calc;
|
||||
groupVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
}
|
||||
}
|
||||
|
||||
list = node->getMember(2);
|
||||
numVars = list->numMembers();
|
||||
|
||||
std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables;
|
||||
aggregateVariables.reserve(numVars);
|
||||
for (size_t i = 0; i < numVars; ++i) {
|
||||
auto assigner = list->getMember(i);
|
||||
|
||||
if (assigner == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_ASSERT(assigner->type == NODE_TYPE_ASSIGN);
|
||||
auto out = assigner->getMember(0);
|
||||
TRI_ASSERT(out != nullptr);
|
||||
auto v = static_cast<Variable*>(out->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
|
||||
auto expression = assigner->getMember(1);
|
||||
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(expression, previous);
|
||||
previous = calc;
|
||||
groupVariables.emplace_back(std::make_pair(v, getOutVariable(calc)));
|
||||
}
|
||||
|
||||
auto collectNode = new CollectNode(
|
||||
this, nextId(), options, groupVariables, nullptr,
|
||||
nullptr, std::vector<Variable const*>(),
|
||||
std::unordered_map<VariableId, std::string const>(), false, false);
|
||||
|
||||
auto en = registerNode(collectNode);
|
||||
|
||||
return addDependency(previous, en);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an execution plan element from an AST LIMIT node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1472,6 +1552,11 @@ ExecutionNode* ExecutionPlan::fromNode(AstNode const* node) {
|
|||
en = fromNodeCollectCount(en, member);
|
||||
break;
|
||||
}
|
||||
|
||||
case NODE_TYPE_COLLECT_AGGREGATE: {
|
||||
en = fromNodeCollectAggregate(en, member);
|
||||
break;
|
||||
}
|
||||
|
||||
case NODE_TYPE_LIMIT: {
|
||||
en = fromNodeLimit(en, member);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define ARANGOD_AQL_EXECUTION_PLAN_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/ModificationOptions.h"
|
||||
#include "Aql/Query.h"
|
||||
|
@ -35,10 +35,10 @@
|
|||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
class AggregateNode;
|
||||
class Ast;
|
||||
struct AstNode;
|
||||
class CalculationNode;
|
||||
class CollectNode;
|
||||
class ExecutionNode;
|
||||
|
||||
|
||||
|
@ -338,7 +338,7 @@ class ExecutionPlan {
|
|||
/// @brief creates an anonymous COLLECT node (for a DISTINCT)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregateNode* createAnonymousCollect(CalculationNode const*);
|
||||
CollectNode* createAnonymousCollect(CalculationNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create modification options from an AST node
|
||||
|
@ -350,7 +350,7 @@ class ExecutionPlan {
|
|||
/// @brief create COLLECT options from an AST node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AggregationOptions createAggregationOptions(AstNode const*);
|
||||
CollectOptions createCollectOptions(AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds "previous" as dependency to "plan", returns "plan"
|
||||
|
@ -406,6 +406,12 @@ class ExecutionPlan {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* fromNodeCollectCount(ExecutionNode*, AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an execution plan element from an AST COLLECT node, AGGREGATE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* fromNodeCollectAggregate(ExecutionNode*, AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an execution plan element from an AST LIMIT node
|
||||
|
|
|
@ -392,7 +392,7 @@ void Optimizer::setupRules() {
|
|||
true);
|
||||
#endif
|
||||
|
||||
// determine the "right" type of AggregateNode and
|
||||
// determine the "right" type of CollectNode and
|
||||
// add a sort node for each COLLECT (may be removed later)
|
||||
// this rule cannot be turned off (otherwise, the query result might be
|
||||
// wrong!)
|
||||
|
|
|
@ -93,7 +93,7 @@ class Optimizer {
|
|||
|
||||
pass1 = 100,
|
||||
|
||||
// determine the "right" type of AggregateNode and
|
||||
// determine the "right" type of CollectNode and
|
||||
// add a sort node for each COLLECT (may be removed later)
|
||||
specializeCollectRule_pass1 = 105,
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "OptimizerRules.h"
|
||||
#include "Aql/AggregateNode.h"
|
||||
#include "Aql/AggregationOptions.h"
|
||||
#include "Aql/CollectOptions.h"
|
||||
#include "Aql/ClusterNodes.h"
|
||||
#include "Aql/CollectNode.h"
|
||||
#include "Aql/ConditionFinder.h"
|
||||
#include "Aql/ExecutionEngine.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
|
@ -440,10 +440,10 @@ void triagens::aql::removeUnnecessaryFiltersRule(Optimizer* opt,
|
|||
void triagens::aql::removeCollectIntoRule(Optimizer* opt, ExecutionPlan* plan,
|
||||
Optimizer::Rule const* rule) {
|
||||
bool modified = false;
|
||||
std::vector<ExecutionNode*> nodes(plan->findNodesOfType(EN::AGGREGATE, true));
|
||||
std::vector<ExecutionNode*> nodes(plan->findNodesOfType(EN::COLLECT, true));
|
||||
|
||||
for (auto const& n : nodes) {
|
||||
auto collectNode = static_cast<AggregateNode*>(n);
|
||||
auto collectNode = static_cast<CollectNode*>(n);
|
||||
TRI_ASSERT(collectNode != nullptr);
|
||||
|
||||
auto outVariable = collectNode->outVariable();
|
||||
|
@ -774,13 +774,13 @@ void triagens::aql::removeSortRandRule(Optimizer* opt, ExecutionPlan* plan,
|
|||
|
||||
switch (current->getType()) {
|
||||
case EN::SORT:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::FILTER:
|
||||
case EN::SUBQUERY:
|
||||
case EN::ENUMERATE_LIST:
|
||||
case EN::TRAVERSAL:
|
||||
case EN::INDEX: {
|
||||
// if we found another SortNode, an AggregateNode, FilterNode, a
|
||||
// if we found another SortNode, an CollectNode, FilterNode, a
|
||||
// SubqueryNode,
|
||||
// an EnumerateListNode, a TraversalNode or an IndexNode
|
||||
// this means we cannot apply our optimization
|
||||
|
@ -965,7 +965,7 @@ void triagens::aql::moveCalculationsDownRule(Optimizer* opt,
|
|||
} else if (currentType == EN::INDEX ||
|
||||
currentType == EN::ENUMERATE_COLLECTION ||
|
||||
currentType == EN::ENUMERATE_LIST ||
|
||||
currentType == EN::TRAVERSAL || currentType == EN::AGGREGATE ||
|
||||
currentType == EN::TRAVERSAL || currentType == EN::COLLECT ||
|
||||
currentType == EN::NORESULTS) {
|
||||
// we will not push further down than such nodes
|
||||
shouldMove = false;
|
||||
|
@ -1108,29 +1108,29 @@ void triagens::aql::fuseCalculationsRule(Optimizer* opt, ExecutionPlan* plan,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determine the "right" type of AggregateNode and
|
||||
/// @brief determine the "right" type of CollectNode and
|
||||
/// add a sort node for each COLLECT (note: the sort may be removed later)
|
||||
/// this rule cannot be turned off (otherwise, the query result might be wrong!)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void triagens::aql::specializeCollectRule(Optimizer* opt, ExecutionPlan* plan,
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes(plan->findNodesOfType(EN::AGGREGATE, true));
|
||||
std::vector<ExecutionNode*> nodes(plan->findNodesOfType(EN::COLLECT, true));
|
||||
bool modified = false;
|
||||
|
||||
for (auto const& n : nodes) {
|
||||
auto collectNode = static_cast<AggregateNode*>(n);
|
||||
auto collectNode = static_cast<CollectNode*>(n);
|
||||
|
||||
if (collectNode->isSpecialized()) {
|
||||
// already specialized this node
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const& aggregateVariables = collectNode->aggregateVariables();
|
||||
auto const& collectVariables = collectNode->collectVariables();
|
||||
|
||||
// test if we can use an alternative version of COLLECT with a hash table
|
||||
bool const canUseHashAggregation =
|
||||
(!aggregateVariables.empty() &&
|
||||
(!collectVariables.empty() &&
|
||||
(!collectNode->hasOutVariable() || collectNode->count()) &&
|
||||
collectNode->getOptions().canUseHashMethod());
|
||||
|
||||
|
@ -1140,21 +1140,21 @@ void triagens::aql::specializeCollectRule(Optimizer* opt, ExecutionPlan* plan,
|
|||
|
||||
// use the cloned COLLECT node
|
||||
auto newCollectNode =
|
||||
static_cast<AggregateNode*>(newPlan->getNodeById(collectNode->id()));
|
||||
static_cast<CollectNode*>(newPlan->getNodeById(collectNode->id()));
|
||||
TRI_ASSERT(newCollectNode != nullptr);
|
||||
|
||||
// specialize the AggregateNode so it will become a HashAggregateBlock
|
||||
// specialize the CollectNode so it will become a HashedCollectBlock
|
||||
// later
|
||||
// additionally, add a SortNode BEHIND the AggregateNode (to sort the
|
||||
// additionally, add a SortNode BEHIND the CollectNode (to sort the
|
||||
// final result)
|
||||
newCollectNode->aggregationMethod(
|
||||
AggregationOptions::AggregationMethod::AGGREGATION_METHOD_HASH);
|
||||
CollectOptions::CollectMethod::COLLECT_METHOD_HASH);
|
||||
newCollectNode->specialized();
|
||||
|
||||
if (!collectNode->isDistinctCommand()) {
|
||||
// add the post-SORT
|
||||
std::vector<std::pair<Variable const*, bool>> sortElements;
|
||||
for (auto const& v : newCollectNode->aggregateVariables()) {
|
||||
for (auto const& v : newCollectNode->collectVariables()) {
|
||||
sortElements.emplace_back(std::make_pair(v.first, true));
|
||||
}
|
||||
|
||||
|
@ -1187,15 +1187,15 @@ void triagens::aql::specializeCollectRule(Optimizer* opt, ExecutionPlan* plan,
|
|||
|
||||
// finally, adjust the original plan and create a sorted version of COLLECT
|
||||
|
||||
// specialize the AggregateNode so it will become a SortedAggregateBlock
|
||||
// specialize the CollectNode so it will become a SortedCollectBlock
|
||||
// later
|
||||
collectNode->aggregationMethod(
|
||||
AggregationOptions::AggregationMethod::AGGREGATION_METHOD_SORTED);
|
||||
CollectOptions::CollectMethod::COLLECT_METHOD_SORTED);
|
||||
|
||||
// insert a SortNode IN FRONT OF the AggregateNode
|
||||
if (!aggregateVariables.empty()) {
|
||||
// insert a SortNode IN FRONT OF the CollectNode
|
||||
if (!collectVariables.empty()) {
|
||||
std::vector<std::pair<Variable const*, bool>> sortElements;
|
||||
for (auto const& v : aggregateVariables) {
|
||||
for (auto const& v : collectVariables) {
|
||||
sortElements.emplace_back(std::make_pair(v.second, true));
|
||||
}
|
||||
|
||||
|
@ -1412,9 +1412,9 @@ class triagens::aql::RedundantCalculationsReplacer final
|
|||
break;
|
||||
}
|
||||
|
||||
case EN::AGGREGATE: {
|
||||
auto node = static_cast<AggregateNode*>(en);
|
||||
for (auto& variable : node->_aggregateVariables) {
|
||||
case EN::COLLECT: {
|
||||
auto node = static_cast<CollectNode*>(en);
|
||||
for (auto& variable : node->_collectVariables) {
|
||||
variable.second = Variable::replace(variable.second, _replacements);
|
||||
}
|
||||
break;
|
||||
|
@ -1541,8 +1541,8 @@ void triagens::aql::removeRedundantCalculationsRule(
|
|||
}
|
||||
}
|
||||
|
||||
if (current->getType() == EN::AGGREGATE) {
|
||||
if (static_cast<AggregateNode*>(current)->hasOutVariable()) {
|
||||
if (current->getType() == EN::COLLECT) {
|
||||
if (static_cast<CollectNode*>(current)->hasOutVariable()) {
|
||||
// COLLECT ... INTO is evil (tm): it needs to keep all already defined
|
||||
// variables
|
||||
// we need to abort optimization here
|
||||
|
@ -1891,7 +1891,7 @@ struct SortToIndexNode final : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
case EN::SINGLETON:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::INSERT:
|
||||
case EN::REMOVE:
|
||||
case EN::REPLACE:
|
||||
|
@ -2568,7 +2568,7 @@ void triagens::aql::distributeFilternCalcToClusterRule(
|
|||
continue;
|
||||
}
|
||||
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::SUBQUERY:
|
||||
case EN::RETURN:
|
||||
case EN::NORESULTS:
|
||||
|
@ -2663,7 +2663,7 @@ void triagens::aql::distributeSortToClusterRule(Optimizer* opt,
|
|||
switch (inspectNode->getType()) {
|
||||
case EN::ENUMERATE_LIST:
|
||||
case EN::SINGLETON:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::INSERT:
|
||||
case EN::REMOVE:
|
||||
case EN::REPLACE:
|
||||
|
@ -2937,7 +2937,7 @@ class RemoveToEnumCollFinder final : public WalkerWorker<ExecutionNode> {
|
|||
case EN::SINGLETON:
|
||||
case EN::ENUMERATE_LIST:
|
||||
case EN::SUBQUERY:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::INSERT:
|
||||
case EN::REPLACE:
|
||||
case EN::UPDATE:
|
||||
|
|
|
@ -103,7 +103,7 @@ void moveCalculationsDownRule(Optimizer*, ExecutionPlan*,
|
|||
void fuseCalculationsRule(Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determine the "right" type of AggregateNode and
|
||||
/// @brief determine the "right" type of CollectNode and
|
||||
/// add a sort node for each COLLECT (may be removed later)
|
||||
/// this rule cannot be turned off (otherwise, the query result might be wrong!)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -227,7 +227,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
|
||||
switch (en->getType()) {
|
||||
case EN::ENUMERATE_LIST:
|
||||
case EN::AGGREGATE:
|
||||
case EN::COLLECT:
|
||||
case EN::SCATTER:
|
||||
case EN::DISTRIBUTE:
|
||||
case EN::GATHER:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -58,59 +58,60 @@ extern int Aqldebug;
|
|||
T_IN = 267,
|
||||
T_WITH = 268,
|
||||
T_INTO = 269,
|
||||
T_GRAPH = 270,
|
||||
T_DISTINCT = 271,
|
||||
T_REMOVE = 272,
|
||||
T_INSERT = 273,
|
||||
T_UPDATE = 274,
|
||||
T_REPLACE = 275,
|
||||
T_UPSERT = 276,
|
||||
T_NULL = 277,
|
||||
T_TRUE = 278,
|
||||
T_FALSE = 279,
|
||||
T_STRING = 280,
|
||||
T_QUOTED_STRING = 281,
|
||||
T_INTEGER = 282,
|
||||
T_DOUBLE = 283,
|
||||
T_PARAMETER = 284,
|
||||
T_ASSIGN = 285,
|
||||
T_NOT = 286,
|
||||
T_AND = 287,
|
||||
T_OR = 288,
|
||||
T_EQ = 289,
|
||||
T_NE = 290,
|
||||
T_LT = 291,
|
||||
T_GT = 292,
|
||||
T_LE = 293,
|
||||
T_GE = 294,
|
||||
T_PLUS = 295,
|
||||
T_MINUS = 296,
|
||||
T_TIMES = 297,
|
||||
T_DIV = 298,
|
||||
T_MOD = 299,
|
||||
T_QUESTION = 300,
|
||||
T_COLON = 301,
|
||||
T_SCOPE = 302,
|
||||
T_RANGE = 303,
|
||||
T_COMMA = 304,
|
||||
T_OPEN = 305,
|
||||
T_CLOSE = 306,
|
||||
T_OBJECT_OPEN = 307,
|
||||
T_OBJECT_CLOSE = 308,
|
||||
T_ARRAY_OPEN = 309,
|
||||
T_ARRAY_CLOSE = 310,
|
||||
T_OUTBOUND = 311,
|
||||
T_INBOUND = 312,
|
||||
T_ANY = 313,
|
||||
T_ALL = 314,
|
||||
T_NONE = 315,
|
||||
T_NIN = 316,
|
||||
UMINUS = 317,
|
||||
UPLUS = 318,
|
||||
FUNCCALL = 319,
|
||||
REFERENCE = 320,
|
||||
INDEXED = 321,
|
||||
EXPANSION = 322
|
||||
T_AGGREGATE = 270,
|
||||
T_GRAPH = 271,
|
||||
T_DISTINCT = 272,
|
||||
T_REMOVE = 273,
|
||||
T_INSERT = 274,
|
||||
T_UPDATE = 275,
|
||||
T_REPLACE = 276,
|
||||
T_UPSERT = 277,
|
||||
T_NULL = 278,
|
||||
T_TRUE = 279,
|
||||
T_FALSE = 280,
|
||||
T_STRING = 281,
|
||||
T_QUOTED_STRING = 282,
|
||||
T_INTEGER = 283,
|
||||
T_DOUBLE = 284,
|
||||
T_PARAMETER = 285,
|
||||
T_ASSIGN = 286,
|
||||
T_NOT = 287,
|
||||
T_AND = 288,
|
||||
T_OR = 289,
|
||||
T_EQ = 290,
|
||||
T_NE = 291,
|
||||
T_LT = 292,
|
||||
T_GT = 293,
|
||||
T_LE = 294,
|
||||
T_GE = 295,
|
||||
T_PLUS = 296,
|
||||
T_MINUS = 297,
|
||||
T_TIMES = 298,
|
||||
T_DIV = 299,
|
||||
T_MOD = 300,
|
||||
T_QUESTION = 301,
|
||||
T_COLON = 302,
|
||||
T_SCOPE = 303,
|
||||
T_RANGE = 304,
|
||||
T_COMMA = 305,
|
||||
T_OPEN = 306,
|
||||
T_CLOSE = 307,
|
||||
T_OBJECT_OPEN = 308,
|
||||
T_OBJECT_CLOSE = 309,
|
||||
T_ARRAY_OPEN = 310,
|
||||
T_ARRAY_CLOSE = 311,
|
||||
T_OUTBOUND = 312,
|
||||
T_INBOUND = 313,
|
||||
T_ANY = 314,
|
||||
T_ALL = 315,
|
||||
T_NONE = 316,
|
||||
T_NIN = 317,
|
||||
UMINUS = 318,
|
||||
UPLUS = 319,
|
||||
FUNCCALL = 320,
|
||||
REFERENCE = 321,
|
||||
INDEXED = 322,
|
||||
EXPANSION = 323
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -129,7 +130,7 @@ union YYSTYPE
|
|||
bool boolval;
|
||||
int64_t intval;
|
||||
|
||||
#line 133 "arangod/Aql/grammar.hpp" /* yacc.c:1909 */
|
||||
#line 134 "arangod/Aql/grammar.hpp" /* yacc.c:1909 */
|
||||
};
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
|
|
@ -72,6 +72,7 @@ void Aqlerror (YYLTYPE* locp,
|
|||
%token T_IN "IN keyword"
|
||||
%token T_WITH "WITH keyword"
|
||||
%token T_INTO "INTO keyword"
|
||||
%token T_AGGREGATE "AGGREGATE keyword"
|
||||
|
||||
%token T_GRAPH "GRAPH keyword"
|
||||
%token T_DISTINCT "DISTINCT modifier"
|
||||
|
@ -125,10 +126,10 @@ void Aqlerror (YYLTYPE* locp,
|
|||
|
||||
%token T_END 0 "end of query string"
|
||||
|
||||
%token T_OUTBOUND "outbound direction"
|
||||
%token T_INBOUND "inbound direction"
|
||||
%token T_ANY "any direction"
|
||||
%token T_OUTBOUND "outbound modifier"
|
||||
%token T_INBOUND "inbound modifier"
|
||||
|
||||
%token T_ANY "any modifier"
|
||||
%token T_ALL "all modifier"
|
||||
%token T_NONE "none modifier"
|
||||
|
||||
|
@ -167,6 +168,7 @@ void Aqlerror (YYLTYPE* locp,
|
|||
%type <node> collect_element;
|
||||
%type <node> collect_variable_list;
|
||||
%type <node> keep;
|
||||
%type <node> aggregate;
|
||||
%type <strval> optional_into;
|
||||
%type <strval> count_into;
|
||||
%type <node> expression;
|
||||
|
@ -347,6 +349,7 @@ collect_variable_list:
|
|||
|
||||
collect_statement:
|
||||
T_COLLECT count_into options {
|
||||
/* COLLECT WITH COUNT INTO var OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
|
@ -363,6 +366,7 @@ collect_statement:
|
|||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list count_into options {
|
||||
/* COLLECT var = expr WITH COUNT INTO var OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
|
@ -389,7 +393,94 @@ collect_statement:
|
|||
auto node = parser->ast()->createNodeCollectCount($1, $2.value, $2.length, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| T_COLLECT aggregate options {
|
||||
/* AGGREGATE var = expr OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
bool reRegisterVariables = (scopes->type() != triagens::aql::AQL_SCOPE_MAIN);
|
||||
|
||||
if (reRegisterVariables) {
|
||||
// end the active scopes
|
||||
scopes->endNested();
|
||||
// start a new scope
|
||||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||
|
||||
size_t const n = $2->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = $2->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||
scopes->addVariable(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectAggregate(parser->ast()->createNodeArray(), $2, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list aggregate options {
|
||||
/* COLLECT var = expr AGGREGATE var = expr OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
bool reRegisterVariables = (scopes->type() != triagens::aql::AQL_SCOPE_MAIN);
|
||||
|
||||
if (reRegisterVariables) {
|
||||
// end the active scopes
|
||||
scopes->endNested();
|
||||
// start a new scope
|
||||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||
|
||||
// register all used variables
|
||||
size_t n = $1->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = $1->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||
scopes->addVariable(v);
|
||||
}
|
||||
}
|
||||
n = $2->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = $2->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||
auto func = member->getMember(1);
|
||||
|
||||
bool isValid = true;
|
||||
if (func->type != NODE_TYPE_FCALL) {
|
||||
// aggregate expression must be a function call
|
||||
isValid = false;
|
||||
}
|
||||
else {
|
||||
auto f = static_cast<triagens::aql::Function*>(func->getData());
|
||||
if (f->externalName != "MIN" && f->externalName != "MAX" && f->externalName != "LENGTH") {
|
||||
// aggregate expression must be a call to MIN|MAX|LENGTH
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! isValid) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "aggregate expression must be a function call", yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||
scopes->addVariable(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectAggregate($1, $2, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list optional_into options {
|
||||
/* COLLECT var = expr INTO var OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
|
@ -416,7 +507,36 @@ collect_statement:
|
|||
auto node = parser->ast()->createNodeCollect($1, $2.value, $2.length, nullptr, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list T_INTO variable_name T_ASSIGN expression options {
|
||||
/* COLLECT var = expr INTO var = expr OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
bool reRegisterVariables = (scopes->type() != triagens::aql::AQL_SCOPE_MAIN);
|
||||
|
||||
if (reRegisterVariables) {
|
||||
// end the active scopes
|
||||
scopes->endNested();
|
||||
// start a new scope
|
||||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||
|
||||
size_t const n = $1->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = $1->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||
scopes->addVariable(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectExpression($1, $3.value, $3.length, $5, $6);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list optional_into keep options {
|
||||
/* COLLECT var = expr INTO var KEEP ... OPTIONS ... */
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
|
@ -448,33 +568,6 @@ collect_statement:
|
|||
auto node = parser->ast()->createNodeCollect($1, $2.value, $2.length, $3, $4);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list T_INTO variable_name T_ASSIGN expression options {
|
||||
auto scopes = parser->ast()->scopes();
|
||||
|
||||
// check if we are in the main scope
|
||||
bool reRegisterVariables = (scopes->type() != triagens::aql::AQL_SCOPE_MAIN);
|
||||
|
||||
if (reRegisterVariables) {
|
||||
// end the active scopes
|
||||
scopes->endNested();
|
||||
// start a new scope
|
||||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||
|
||||
size_t const n = $1->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = $1->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
|
||||
auto v = static_cast<Variable*>(member->getMember(0)->getData());
|
||||
scopes->addVariable(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectExpression($1, $3.value, $3.length, $5, $6);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
;
|
||||
|
||||
collect_list:
|
||||
|
@ -547,6 +640,16 @@ keep:
|
|||
}
|
||||
;
|
||||
|
||||
aggregate:
|
||||
T_AGGREGATE {
|
||||
auto node = parser->ast()->createNodeArray();
|
||||
parser->pushStack(node);
|
||||
} collect_list {
|
||||
auto list = static_cast<AstNode*>(parser->popStack());
|
||||
$$ = list;
|
||||
}
|
||||
;
|
||||
|
||||
sort_statement:
|
||||
T_SORT {
|
||||
auto node = parser->ast()->createNodeArray();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -93,6 +93,10 @@ namespace triagens {
|
|||
return T_DISTINCT;
|
||||
}
|
||||
|
||||
(?i:AGGREGATE) {
|
||||
return T_AGGREGATE;
|
||||
}
|
||||
|
||||
(?i:ASC) {
|
||||
return T_ASC;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,6 @@ add_executable(
|
|||
Actions/RestActionHandler.cpp
|
||||
ApplicationServer/ApplicationFeature.cpp
|
||||
ApplicationServer/ApplicationServer.cpp
|
||||
Aql/AggregateBlock.cpp
|
||||
Aql/AggregateNode.cpp
|
||||
Aql/AggregationOptions.cpp
|
||||
Aql/AqlItemBlock.cpp
|
||||
Aql/AqlItemBlockManager.cpp
|
||||
Aql/AqlValue.cpp
|
||||
|
@ -77,6 +74,9 @@ add_executable(
|
|||
Aql/Collection.cpp
|
||||
Aql/Collections.cpp
|
||||
Aql/CollectionScanner.cpp
|
||||
Aql/CollectBlock.cpp
|
||||
Aql/CollectNode.cpp
|
||||
Aql/CollectOptions.cpp
|
||||
Aql/Condition.cpp
|
||||
Aql/ConditionFinder.cpp
|
||||
Aql/EnumerateCollectionBlock.cpp
|
||||
|
|
|
@ -17,9 +17,6 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/Actions/RestActionHandler.cpp \
|
||||
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 \
|
||||
arangod/Aql/AqlValue.cpp \
|
||||
|
@ -34,6 +31,9 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/Aql/Collection.cpp \
|
||||
arangod/Aql/Collections.cpp \
|
||||
arangod/Aql/CollectionScanner.cpp \
|
||||
arangod/Aql/CollectBlock.cpp \
|
||||
arangod/Aql/CollectNode.cpp \
|
||||
arangod/Aql/CollectOptions.cpp \
|
||||
arangod/Aql/Condition.cpp \
|
||||
arangod/Aql/ConditionFinder.cpp \
|
||||
arangod/Aql/EnumerateCollectionBlock.cpp \
|
||||
|
|
|
@ -795,6 +795,7 @@ function processQuery (query, explain) {
|
|||
case "FilterNode":
|
||||
return keyword("FILTER") + " " + variableName(node.inVariable);
|
||||
case "AggregateNode":
|
||||
case "CollectNode":
|
||||
return keyword("COLLECT") + " " + node.aggregates.map(function(node) {
|
||||
return variableName(node.outVariable) + " = " + variableName(node.inVariable);
|
||||
}).join(", ") +
|
||||
|
|
|
@ -794,6 +794,7 @@ function processQuery (query, explain) {
|
|||
case "FilterNode":
|
||||
return keyword("FILTER") + " " + variableName(node.inVariable);
|
||||
case "AggregateNode":
|
||||
case "CollectNode":
|
||||
return keyword("COLLECT") + " " + node.aggregates.map(function(node) {
|
||||
return variableName(node.outVariable) + " = " + variableName(node.inVariable);
|
||||
}).join(", ") +
|
||||
|
|
|
@ -282,7 +282,7 @@ function explainSuite () {
|
|||
prev = node.id;
|
||||
|
||||
node = nodes[n++];
|
||||
assertEqual("AggregateNode", node.type);
|
||||
assertEqual("CollectNode", node.type);
|
||||
assertEqual([ prev ], node.dependencies);
|
||||
assertEqual(1, node.aggregates.length);
|
||||
assertEqual("a", node.aggregates[0].inVariable.name);
|
||||
|
|
|
@ -258,7 +258,7 @@ function explainSuite () {
|
|||
assertTrue(node.stable);
|
||||
|
||||
node = nodes[7];
|
||||
assertEqual("AggregateNode", node.type);
|
||||
assertEqual("CollectNode", node.type);
|
||||
assertEqual([ 9 ], node.dependencies);
|
||||
assertEqual(7, node.id);
|
||||
assertEqual(1, node.aggregates.length);
|
||||
|
|
|
@ -126,7 +126,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.aggregationOptions.method);
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.aggregationOptions.method);
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("sorted", node.aggregationOptions.method);
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("hash", node.aggregationOptions.method);
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("sorted", node.aggregationOptions.method);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ function optimizerCollectMethodsTestSuite () {
|
|||
var aggregateNodes = 0;
|
||||
var sortNodes = 0;
|
||||
plan.nodes.map(function(node) {
|
||||
if (node.type === "AggregateNode") {
|
||||
if (node.type === "CollectNode") {
|
||||
++aggregateNodes;
|
||||
assertEqual("sorted", node.aggregationOptions.method);
|
||||
}
|
||||
|
|
|
@ -117,9 +117,9 @@ function optimizerRuleTestSuite () {
|
|||
|
||||
testPlans : function () {
|
||||
var plans = [
|
||||
[ "FOR i IN 1..10 COLLECT a = i INTO group RETURN a", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "SortNode", "AggregateNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN 1..10 FOR j IN 1..10 COLLECT a = i, b = j INTO group RETURN a", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "EnumerateListNode", "SortNode", "AggregateNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN 1..10 FOR j IN 1..10 COLLECT a = i, b = j INTO group RETURN { a: a, b : b }", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "EnumerateListNode", "SortNode", "AggregateNode", "CalculationNode", "ReturnNode" ] ]
|
||||
[ "FOR i IN 1..10 COLLECT a = i INTO group RETURN a", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "SortNode", "CollectNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN 1..10 FOR j IN 1..10 COLLECT a = i, b = j INTO group RETURN a", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "EnumerateListNode", "SortNode", "CollectNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN 1..10 FOR j IN 1..10 COLLECT a = i, b = j INTO group RETURN { a: a, b : b }", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "EnumerateListNode", "SortNode", "CollectNode", "CalculationNode", "ReturnNode" ] ]
|
||||
];
|
||||
|
||||
plans.forEach(function(plan) {
|
||||
|
|
|
@ -133,7 +133,7 @@ function optimizerRuleTestSuite () {
|
|||
[ "FOR i IN [ { a: 1 }, { a: 2 }, { a: 3 } ] SORT i.a DESC SORT i.a DESC RETURN i", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "SortNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a ASC, i.b DESC SORT i.a DESC, i.b ASC RETURN i", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "CalculationNode", "SortNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a ASC, i.b DESC FILTER i.a == 1 SORT i.a DESC, i.b ASC RETURN i", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "FilterNode", "CalculationNode", "CalculationNode", "SortNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a ASC COLLECT x = i.a RETURN x", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "SortNode", "AggregateNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a ASC COLLECT x = i.a RETURN x", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "SortNode", "CollectNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a, i.b SORT i.a SORT i.a RETURN i", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "CalculationNode", "SortNode", "ReturnNode" ] ],
|
||||
[ "FOR i IN [ { a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 1 } ] SORT i.a, i.b SORT i.a DESC SORT i.a ASC RETURN i", [ "SingletonNode", "CalculationNode", "EnumerateListNode", "CalculationNode", "CalculationNode", "SortNode", "ReturnNode" ] ]
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue