mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
068faf709b
|
@ -438,11 +438,11 @@ void IndexRangeNode::toJsonHelper (triagens::basics::Json& nodes,
|
|||
}
|
||||
|
||||
// Now put info about vocbase and cid in there
|
||||
json("database", Json(_vocbase->_name))
|
||||
/*json("database", Json(_vocbase->_name))
|
||||
("collection", Json(_collection->name))
|
||||
("outVariable", _outVariable->toJson())
|
||||
("index", _index->index()->json(_index->index()))
|
||||
("ranges", ranges);
|
||||
("ranges", ranges);*/
|
||||
|
||||
// And add it:
|
||||
nodes(json);
|
||||
|
|
|
@ -178,6 +178,24 @@ namespace triagens {
|
|||
return _dependencies;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace a dependency, returns true if the pointer was found and
|
||||
/// replaced, please note that this does not delete oldNode!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool replaceDependency (ExecutionNode* oldNode, ExecutionNode* newNode) {
|
||||
auto it = _dependencies.begin();
|
||||
|
||||
while (it != _dependencies.end()) {
|
||||
if (*it == oldNode) {
|
||||
*it = newNode;
|
||||
return true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove a dependency, returns true if the pointer was found and
|
||||
/// removed, please note that this does not delete ep!
|
||||
|
@ -545,6 +563,56 @@ namespace triagens {
|
|||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get indexes with fields <attrs> or nullptr if none exist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
vector<TRI_index_t*> getIndexes (vector<std::string> attrs) const {
|
||||
vector<TRI_index_t*> out;
|
||||
TRI_document_collection_t* document = _collection->documentCollection();
|
||||
size_t const n = document->_allIndexes._length;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_index_t* idx = static_cast<TRI_index_t*>(document->_allIndexes._buffer[i]);
|
||||
|
||||
size_t seen = 0;
|
||||
for (size_t j = 0; j < idx->_fields._length; j++) {
|
||||
bool found = false;
|
||||
for (size_t k = 0; k < attrs.size(); k++){
|
||||
if(std::string(idx->_fields._buffer[j]) == attrs[k]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
seen++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((idx->_type == TRI_IDX_TYPE_HASH_INDEX) && seen == idx->_fields._length )
|
||||
|| ((idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) && seen > 0 )) {
|
||||
// all fields equal
|
||||
out.push_back(idx);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase () const {
|
||||
return _vocbase;
|
||||
}
|
||||
|
||||
Collection* collection () const {
|
||||
return _collection;
|
||||
}
|
||||
|
||||
Variable const* outVariable () const {
|
||||
return _outVariable;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -555,7 +623,7 @@ namespace triagens {
|
|||
/// @brief the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* _vocbase;
|
||||
TRI_vocbase_t* _vocbase;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collection
|
||||
|
@ -567,7 +635,7 @@ namespace triagens {
|
|||
/// @brief output variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* _outVariable;
|
||||
Variable const* _outVariable;
|
||||
|
||||
};
|
||||
|
||||
|
@ -798,28 +866,46 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
|
||||
~RangesInfo(){}
|
||||
|
||||
RangeInfo* find(std::string name) const {
|
||||
auto it = _ranges.find(name);
|
||||
RangeInfo* find(std::string var, std::string name) const {
|
||||
auto it1 = _ranges.find(var);
|
||||
if (it1 == _ranges.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto it2 = it1->second.find(name);
|
||||
if (it2 == it1->second.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*it2).second;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, RangeInfo*>* find(std::string var) {
|
||||
auto it = _ranges.find(var);
|
||||
if (it == _ranges.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*it).second;
|
||||
//std::unordered_map<std::string, RangeInfo*>* out = &((*it).second);
|
||||
//return out;
|
||||
return &((*it).second);
|
||||
}
|
||||
|
||||
/*void insert (std::string name, RangeInfo* range) {
|
||||
if( find(name) == nullptr ){
|
||||
_ranges.insert(make_pair(name, range));
|
||||
}
|
||||
}*/
|
||||
|
||||
void insert (std::string name, RangeInfoBound* low, RangeInfoBound* high){
|
||||
auto oldRange = find(name);
|
||||
auto newRange = new RangeInfo(low, high);
|
||||
int cmp;
|
||||
|
||||
if( oldRange == nullptr ){
|
||||
void insert (std::string var, std::string name,
|
||||
RangeInfoBound* low, RangeInfoBound* high) {
|
||||
auto oldMap = find(var);
|
||||
auto newRange = new RangeInfo(low, high);
|
||||
|
||||
if (oldMap == nullptr) {
|
||||
// TODO add exception . . .
|
||||
_ranges.insert(make_pair(name, newRange));
|
||||
auto newMap = std::unordered_map<std::string, RangeInfo*>();
|
||||
newMap.insert(make_pair(name, newRange));
|
||||
_ranges.insert(std::make_pair(var, newMap));
|
||||
return;
|
||||
}
|
||||
|
||||
auto oldRange = find(var, name); //TODO improve
|
||||
|
||||
if (oldRange == nullptr) {
|
||||
// TODO add exception . . .
|
||||
oldMap->insert(make_pair(name, newRange));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -837,7 +923,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
|
||||
// check the new range bounds are valid
|
||||
if( oldRange->_low != nullptr && oldRange->_high != nullptr){
|
||||
cmp = TRI_CompareValuesJson(oldRange->_low->_bound.json(),
|
||||
int cmp = TRI_CompareValuesJson(oldRange->_low->_bound.json(),
|
||||
oldRange->_high->_bound.json());
|
||||
if (cmp == 1 || (cmp == 0 &&
|
||||
!(oldRange->_low->_include == true && oldRange->_high->_include == true ))){
|
||||
|
@ -852,7 +938,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
return _ranges.size();
|
||||
}
|
||||
|
||||
Json toJson () const {
|
||||
/*Json toJson () const {
|
||||
Json list(Json::List);
|
||||
for (auto x : _ranges) {
|
||||
Json item(Json::Array);
|
||||
|
@ -865,10 +951,10 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
|
||||
std::string toString() const {
|
||||
return this->toJson().toString();
|
||||
}
|
||||
}*/
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, RangeInfo*> _ranges;
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, RangeInfo*>> _ranges;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -891,7 +977,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
TRI_vocbase_t* vocbase,
|
||||
Collection* collection,
|
||||
Variable const* outVariable,
|
||||
Index* index,
|
||||
TRI_index_t* index,
|
||||
vector<RangeInfo*>* ranges)
|
||||
: ExecutionNode(id),
|
||||
_vocbase(vocbase),
|
||||
|
@ -984,7 +1070,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
|||
/// @brief the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Index* _index;
|
||||
TRI_index_t* _index;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the range info
|
||||
|
|
|
@ -51,12 +51,10 @@ using JsonHelper = triagens::basics::JsonHelper;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionPlan::ExecutionPlan ()
|
||||
: _nodes(),
|
||||
_ids(),
|
||||
: _ids(),
|
||||
_root(nullptr),
|
||||
_nextId(0) {
|
||||
|
||||
_nodes.reserve(8);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -64,8 +62,8 @@ ExecutionPlan::ExecutionPlan ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionPlan::~ExecutionPlan () {
|
||||
for (auto it = _nodes.begin(); it != _nodes.end(); ++it) {
|
||||
delete (*it);
|
||||
for (auto x : _ids){
|
||||
delete x.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,23 +187,36 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a node to the plan, will delete node if addition fails
|
||||
/// @brief register a node with the plan, will delete node if addition fails
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* ExecutionPlan::addNode (ExecutionNode* node) {
|
||||
ExecutionNode* ExecutionPlan::registerNode (ExecutionNode* node) {
|
||||
TRI_ASSERT(node != nullptr);
|
||||
TRI_ASSERT(node->id() > 0);
|
||||
|
||||
try {
|
||||
_nodes.push_back(node);
|
||||
_ids.insert(std::make_pair(node->id(), node));
|
||||
|
||||
return node;
|
||||
}
|
||||
catch (...) {
|
||||
delete node;
|
||||
throw;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief unregister a node to the plan
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExecutionPlan::unregisterNode (ExecutionNode* node) {
|
||||
TRI_ASSERT(node != nullptr);
|
||||
TRI_ASSERT(node->id() > 0);
|
||||
|
||||
auto it = _ids.find(node->id());
|
||||
TRI_ASSERT(it != _ids.end());
|
||||
TRI_ASSERT(it->second == node);
|
||||
|
||||
_ids.erase(it);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -224,9 +235,10 @@ CalculationNode* ExecutionPlan::createTemporaryCalculation (Ast const* ast,
|
|||
try {
|
||||
auto en = new CalculationNode(nextId(), expr, out);
|
||||
|
||||
addNode(reinterpret_cast<ExecutionNode*>(en));
|
||||
registerNode(reinterpret_cast<ExecutionNode*>(en));
|
||||
return en;
|
||||
}
|
||||
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
delete expr;
|
||||
|
@ -285,20 +297,20 @@ ExecutionNode* ExecutionPlan::fromNodeFor (Ast const* ast,
|
|||
if (collection == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "no collection for EnumerateCollection");
|
||||
}
|
||||
en = addNode(new EnumerateCollectionNode(nextId(), ast->query()->vocbase(), collection, v));
|
||||
en = registerNode(new EnumerateCollectionNode(nextId(), ast->query()->vocbase(), collection, v));
|
||||
}
|
||||
else if (expression->type == NODE_TYPE_REFERENCE) {
|
||||
// second operand is already a variable
|
||||
auto inVariable = static_cast<Variable*>(expression->getData());
|
||||
TRI_ASSERT(inVariable != nullptr);
|
||||
en = addNode(new EnumerateListNode(nextId(), inVariable, v));
|
||||
en = registerNode(new EnumerateListNode(nextId(), inVariable, v));
|
||||
}
|
||||
else {
|
||||
// second operand is some misc. expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
|
||||
en = registerNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -325,14 +337,14 @@ ExecutionNode* ExecutionPlan::fromNodeFilter (Ast const* ast,
|
|||
// operand is already a variable
|
||||
auto v = static_cast<Variable*>(expression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new FilterNode(nextId(), v));
|
||||
en = registerNode(new FilterNode(nextId(), v));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new FilterNode(nextId(), calc->outVariable()));
|
||||
en = registerNode(new FilterNode(nextId(), calc->outVariable()));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -366,14 +378,14 @@ ExecutionNode* ExecutionPlan::fromNodeLet (Ast const* ast,
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
en = addNode(new SubqueryNode(nextId(), subquery, v));
|
||||
en = registerNode(new SubqueryNode(nextId(), subquery, v));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression, including references to other variables
|
||||
auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression));
|
||||
|
||||
try {
|
||||
en = addNode(new CalculationNode(nextId(), expr, v));
|
||||
en = registerNode(new CalculationNode(nextId(), expr, v));
|
||||
}
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
|
@ -441,7 +453,7 @@ ExecutionNode* ExecutionPlan::fromNodeSort (Ast const* ast,
|
|||
previous = (*it);
|
||||
}
|
||||
|
||||
auto en = addNode(new SortNode(nextId(), elements));
|
||||
auto en = registerNode(new SortNode(nextId(), elements));
|
||||
|
||||
return addDependency(previous, en);
|
||||
}
|
||||
|
@ -501,7 +513,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
|
|||
}
|
||||
|
||||
// inject a sort node for all expressions / variables that we just picked up...
|
||||
auto sort = addNode(new SortNode(nextId(), sortElements));
|
||||
auto sort = registerNode(new SortNode(nextId(), sortElements));
|
||||
sort->addDependency(previous);
|
||||
previous = sort;
|
||||
|
||||
|
@ -514,7 +526,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
|
|||
outVariable = static_cast<Variable*>(v->getData());
|
||||
}
|
||||
|
||||
auto en = addNode(new AggregateNode(nextId(), aggregateVariables, outVariable, ast->variables()->variables(false)));
|
||||
auto en = registerNode(new AggregateNode(nextId(), aggregateVariables, outVariable, ast->variables()->variables(false)));
|
||||
|
||||
return addDependency(previous, en);
|
||||
}
|
||||
|
@ -535,7 +547,7 @@ ExecutionNode* ExecutionPlan::fromNodeLimit (Ast const* ast,
|
|||
TRI_ASSERT(offset->type == NODE_TYPE_VALUE);
|
||||
TRI_ASSERT(count->type == NODE_TYPE_VALUE);
|
||||
|
||||
auto en = addNode(new LimitNode(nextId(), static_cast<size_t>(offset->getIntValue()), static_cast<size_t>(count->getIntValue())));
|
||||
auto en = registerNode(new LimitNode(nextId(), static_cast<size_t>(offset->getIntValue()), static_cast<size_t>(count->getIntValue())));
|
||||
|
||||
return addDependency(previous, en);
|
||||
}
|
||||
|
@ -558,13 +570,13 @@ ExecutionNode* ExecutionPlan::fromNodeReturn (Ast const* ast,
|
|||
// operand is already a variable
|
||||
auto v = static_cast<Variable*>(expression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new ReturnNode(nextId(), v));
|
||||
en = registerNode(new ReturnNode(nextId(), v));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new ReturnNode(nextId(), calc->outVariable()));
|
||||
en = registerNode(new ReturnNode(nextId(), calc->outVariable()));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -597,13 +609,13 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
|
|||
// operand is already a variable
|
||||
auto v = static_cast<Variable*>(expression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
|
||||
en = registerNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||
en = registerNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -631,13 +643,13 @@ ExecutionNode* ExecutionPlan::fromNodeInsert (Ast const* ast,
|
|||
// operand is already a variable
|
||||
auto v = static_cast<Variable*>(expression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
|
||||
en = registerNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, expression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||
en = registerNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -683,13 +695,13 @@ ExecutionNode* ExecutionPlan::fromNodeUpdate (Ast const* ast,
|
|||
// document operand is already a variable
|
||||
auto v = static_cast<Variable*>(docExpression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
|
||||
en = registerNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
|
||||
}
|
||||
else {
|
||||
// document operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, docExpression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
|
||||
en = registerNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -735,13 +747,13 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
|
|||
// operand is already a variable
|
||||
auto v = static_cast<Variable*>(docExpression->getData());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
en = addNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
|
||||
en = registerNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
|
||||
}
|
||||
else {
|
||||
// operand is some misc expression
|
||||
auto calc = createTemporaryCalculation(ast, docExpression);
|
||||
calc->addDependency(previous);
|
||||
en = addNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
|
||||
en = registerNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
|
||||
previous = calc;
|
||||
}
|
||||
|
||||
|
@ -756,7 +768,7 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
|
|||
AstNode const* node) {
|
||||
TRI_ASSERT(node != nullptr);
|
||||
|
||||
ExecutionNode* en = addNode(new SingletonNode(nextId()));
|
||||
ExecutionNode* en = registerNode(new SingletonNode(nextId()));
|
||||
|
||||
size_t const n = node->numMembers();
|
||||
|
||||
|
@ -936,7 +948,7 @@ void ExecutionPlan::findVarUsage () {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper struct for removeNodes
|
||||
/// @brief helper struct for unlinkNodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
||||
|
@ -963,6 +975,7 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
else {
|
||||
auto dep = en->getDependencies();
|
||||
//TODO make exception safe
|
||||
parents.back()->removeDependency(en);
|
||||
if (dep.size() == 1) {
|
||||
parents.back()->addDependency(dep[0]);
|
||||
|
@ -977,29 +990,87 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
void after (ExecutionNode* en) {
|
||||
_plan->unregisterNode(en);
|
||||
parents.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removeNodes, note that this does not delete the removed
|
||||
/// @brief unlinkNodes, note that this does not delete the removed
|
||||
/// nodes and that one cannot remove the root node of the plan.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExecutionPlan::removeNodes (std::unordered_set<ExecutionNode*>& toRemove) {
|
||||
void ExecutionPlan::unlinkNodes (std::unordered_set<ExecutionNode*>& toRemove) {
|
||||
NodeRemover remover(this, toRemove);
|
||||
root()->walk(&remover);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removeNode, note that this does not delete the removed
|
||||
/// @brief unlinkNode, note that this does not delete the removed
|
||||
/// node and that one cannot remove the root node of the plan.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExecutionPlan::removeNode (ExecutionNode* node) {
|
||||
std::unordered_set<ExecutionNode*> toRemove;
|
||||
toRemove.insert(node);
|
||||
return removeNodes(toRemove);
|
||||
void ExecutionPlan::unlinkNode (ExecutionNode* node) {
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
toUnlink.insert(node);
|
||||
return unlinkNodes(toUnlink);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replaceNode, note that <newNode> must be registered with the plan
|
||||
/// before this method is called, also this does not delete the old
|
||||
/// node and that one cannot replace the root node of the plan.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExecutionPlan::replaceNode (ExecutionNode* oldNode, ExecutionNode* newNode,
|
||||
ExecutionNode* oldNodeParent) {
|
||||
TRI_ASSERT(oldNode->id() != newNode->id());
|
||||
TRI_ASSERT(newNode->getDependencies().size() ==0);
|
||||
TRI_ASSERT(oldNode != _root);
|
||||
|
||||
std::vector<ExecutionNode*> deps = oldNode->getDependencies();
|
||||
|
||||
for (auto x : deps) {
|
||||
newNode->addDependency(x);
|
||||
}
|
||||
|
||||
if(!oldNodeParent->replaceDependency(oldNode, newNode)){
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"Could not replace dependencies of an old node.");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone the plan by recursively cloning starting from the root
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CloneNodeAdder : public WalkerWorker<ExecutionNode> {
|
||||
ExecutionPlan* _plan;
|
||||
|
||||
public:
|
||||
|
||||
CloneNodeAdder (ExecutionPlan* plan) : _plan(plan){}
|
||||
|
||||
~CloneNodeAdder (){}
|
||||
|
||||
void before (ExecutionNode* node){
|
||||
_plan->registerNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionPlan* ExecutionPlan::clone (){
|
||||
auto plan = new ExecutionPlan();
|
||||
try {
|
||||
plan->_root = _root->clone();
|
||||
CloneNodeAdder adder(plan);
|
||||
plan->_root->walk(&adder);
|
||||
plan->findVarUsage();
|
||||
return plan;
|
||||
}
|
||||
catch (...) {
|
||||
delete plan;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1029,7 +1100,7 @@ ExecutionNode* ExecutionPlan::fromJson (Ast* ast,
|
|||
ret = ExecutionNode::fromJsonFactory(ast,
|
||||
oneJsonNode);
|
||||
|
||||
addNode(ret);
|
||||
registerNode(ret);
|
||||
|
||||
TRI_ASSERT(ret != nullptr);
|
||||
|
||||
|
|
|
@ -146,18 +146,43 @@ namespace triagens {
|
|||
void findVarUsage ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removeNodes, note that this does not delete the removed
|
||||
/// @brief unlinkNodes, note that this does not delete the removed
|
||||
/// nodes and that one cannot remove the root node of the plan.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void removeNodes (std::unordered_set<ExecutionNode*>& toRemove);
|
||||
void unlinkNodes (std::unordered_set<ExecutionNode*>& toUnlink);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removeNode, note that this does not delete the removed
|
||||
/// @brief unlinkNode, note that this does not delete the removed
|
||||
/// node and that one cannot remove the root node of the plan.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void removeNode (ExecutionNode*);
|
||||
void unlinkNode (ExecutionNode*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a node to the plan, will delete node if addition fails
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* registerNode (ExecutionNode*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief unregister a node to the plan
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void unregisterNode (ExecutionNode* node);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace oldNode with newNode and fix dependencies
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void replaceNode (ExecutionNode* oldNode, ExecutionNode* newNode,
|
||||
ExecutionNode* oldNodeParent);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clone the plan by recursively cloning starting from the root
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionPlan* clone ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
|
@ -171,11 +196,6 @@ namespace triagens {
|
|||
|
||||
ModificationOptions createOptions (AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a node to the plan, will delete node if addition fails
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExecutionNode* addNode (ExecutionNode*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a calculation node for an arbitrary expression
|
||||
|
@ -295,12 +315,6 @@ namespace triagens {
|
|||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief all nodes registered, used for memory management
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<ExecutionNode*> _nodes;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief map from node id to the actual node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -79,8 +79,6 @@ namespace triagens {
|
|||
return this->index()->_type;
|
||||
}
|
||||
|
||||
|
||||
// anything else??
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -42,7 +42,7 @@ Optimizer::Optimizer () {
|
|||
// List all the rules in the system here:
|
||||
|
||||
// try to find a filter after an enumerate collection and find an index . . .
|
||||
// registerRule (useIndexRange, 999);
|
||||
registerRule (useIndexRange, 999);
|
||||
|
||||
// remove filters from the query that are not necessary at all
|
||||
// filters that are always true will be removed entirely
|
||||
|
|
|
@ -50,7 +50,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
bool& keep) {
|
||||
|
||||
keep = true; // plan will always be kept
|
||||
std::unordered_set<ExecutionNode*> toRemove;
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||
|
||||
for (auto n : nodes) {
|
||||
|
@ -84,21 +84,20 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
if (root->toBoolean()) {
|
||||
// filter is always true
|
||||
// remove filter node and merge with following node
|
||||
toRemove.insert(n);
|
||||
toUnlink.insert(n);
|
||||
}
|
||||
else {
|
||||
// filter is always false
|
||||
// TODO: insert a NoResults node below it
|
||||
//auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId()));
|
||||
//TRI_ASSERT(noResultsNode != nullptr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (! toRemove.empty()) {
|
||||
std::cout << "Removing " << toRemove.size() << " unnecessary "
|
||||
if (! toUnlink.empty()) {
|
||||
std::cout << "Removing " << toUnlink.size() << " unnecessary "
|
||||
"nodes..." << std::endl;
|
||||
plan->removeNodes(toRemove);
|
||||
plan->unlinkNodes(toUnlink);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -171,7 +170,7 @@ std::cout << "LOOKING AT NODE OF TYPE: " << current->getTypeString() << "\n";
|
|||
// no shared variables found. we can move the calculation up the dependency chain
|
||||
|
||||
// first, delete the calculation from the plan
|
||||
plan->removeNode(n);
|
||||
plan->unlinkNode(n);
|
||||
|
||||
// fiddle dependencies of calculation node
|
||||
n->removeDependencies();
|
||||
|
@ -208,7 +207,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
|||
keep = true;
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
|
||||
std::unordered_set<ExecutionNode*> toRemove;
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
for (auto n : nodes) {
|
||||
auto nn = static_cast<CalculationNode*>(n);
|
||||
|
||||
|
@ -225,14 +224,14 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
|||
// The variable whose value is calculated here is not used at
|
||||
// all further down the pipeline! We remove the whole
|
||||
// calculation node,
|
||||
toRemove.insert(n);
|
||||
toUnlink.insert(n);
|
||||
}
|
||||
}
|
||||
|
||||
if (! toRemove.empty()) {
|
||||
std::cout << "Removing " << toRemove.size() << " unnecessary "
|
||||
if (! toUnlink.empty()) {
|
||||
std::cout << "Removing " << toUnlink.size() << " unnecessary "
|
||||
"CalculationNodes..." << std::endl;
|
||||
plan->removeNodes(toRemove);
|
||||
plan->unlinkNodes(toUnlink);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -246,10 +245,14 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
|||
RangesInfo* _ranges;
|
||||
ExecutionPlan* _plan;
|
||||
Variable const* _var;
|
||||
Optimizer::PlanList _out;
|
||||
ExecutionNode* _prev;
|
||||
|
||||
//EnumerateCollectionNode const* _enumColl;
|
||||
|
||||
public:
|
||||
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var)
|
||||
: _plan(plan), _var(var){
|
||||
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out)
|
||||
: _plan(plan), _var(var), _out(out), _prev(nullptr){
|
||||
_ranges = new RangesInfo();
|
||||
};
|
||||
|
||||
|
@ -259,29 +262,73 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
|||
TRI_ASSERT(outvar.size() == 1);
|
||||
if(outvar[0]->id == _var->id){
|
||||
auto node = static_cast<CalculationNode*>(en);
|
||||
std::string name;
|
||||
buildRangeInfo(node->expression()->node(), name);
|
||||
std::string attr;
|
||||
std::string enumCollVar;
|
||||
buildRangeInfo(node->expression()->node(), enumCollVar, attr);
|
||||
}
|
||||
}
|
||||
else if (en->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION) {
|
||||
auto node = static_cast<EnumerateCollectionNode*>(en);
|
||||
auto var = node->getVariablesSetHere()[0]; // should only be 1
|
||||
auto map = _ranges->find(var->name); // check if we have any ranges with this var
|
||||
|
||||
if (map != nullptr) {
|
||||
// check the first components of <map> against indexes of <node> . . .
|
||||
// FIXME does this need to be done like this? Couldn't we keep track
|
||||
// earlier?
|
||||
std::vector<std::string> attrs;
|
||||
std::vector<RangeInfo*> rangeInfo;
|
||||
for (auto x : *map){
|
||||
attrs.push_back(x.first);
|
||||
rangeInfo.push_back(x.second);
|
||||
}
|
||||
std::vector<TRI_index_t*> idxs = node->getIndexes(attrs);
|
||||
|
||||
//use make one new plan for every index in <idxs> that replaces the
|
||||
//enumerate collection node with a RangeIndexNode . . .
|
||||
for (auto idx: idxs) {
|
||||
std::cout << "FOUND INDEX!\n";
|
||||
auto newPlan = _plan->clone();
|
||||
ExecutionNode* newNode = nullptr;
|
||||
try{
|
||||
newNode = new IndexRangeNode( newPlan->nextId(), node->vocbase(),
|
||||
node->collection(), node->outVariable(), idx, &rangeInfo);
|
||||
newPlan->registerNode(newNode);
|
||||
}
|
||||
catch (...) {
|
||||
if (newNode != nullptr) {
|
||||
delete newNode;
|
||||
}
|
||||
delete newPlan;
|
||||
throw;
|
||||
}
|
||||
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode,
|
||||
newPlan->getNodeById(_prev->id()));
|
||||
std::cout << newPlan->root()->toJson().toString() << "\n";
|
||||
_out.push_back(newPlan);
|
||||
}
|
||||
}
|
||||
}
|
||||
_prev = en;
|
||||
}
|
||||
|
||||
void buildRangeInfo (AstNode const* node, std::string& name){
|
||||
void buildRangeInfo (AstNode const* node, std::string& enumCollVar, std::string& attr){
|
||||
if(node->type == NODE_TYPE_REFERENCE){
|
||||
auto var = static_cast<Variable*>(node->getData());
|
||||
auto setter = _plan->getVarSetBy(var->id);
|
||||
auto x = static_cast<Variable*>(node->getData());
|
||||
auto setter = _plan->getVarSetBy(x->id);
|
||||
if( setter != nullptr &&
|
||||
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
|
||||
name = var->name;
|
||||
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
|
||||
enumCollVar = x->name;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){
|
||||
char const* attributeName = node->getStringValue();
|
||||
buildRangeInfo(node->getMember(0), name);
|
||||
if(!name.empty()){
|
||||
name.push_back('.');
|
||||
name.append(attributeName);
|
||||
buildRangeInfo(node->getMember(0), enumCollVar, attr);
|
||||
if(!enumCollVar.empty()){
|
||||
attr.append(attributeName);
|
||||
attr.push_back('.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,14 +350,13 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
if(val != nullptr){
|
||||
buildRangeInfo(nextNode, name);
|
||||
if(!name.empty()){
|
||||
_ranges->insert(name, new RangeInfoBound(val, true),
|
||||
new RangeInfoBound(val, true));
|
||||
buildRangeInfo(nextNode, enumCollVar, attr);
|
||||
if(!enumCollVar.empty()){
|
||||
_ranges->insert(enumCollVar, attr.substr(0, attr.size()-1),
|
||||
new RangeInfoBound(val, true), new RangeInfoBound(val, true));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << _ranges->toString() << "\n";
|
||||
//std::cout << _ranges->toString() << "\n";
|
||||
}
|
||||
|
||||
if(node->type == NODE_TYPE_OPERATOR_BINARY_LT ||
|
||||
|
@ -355,21 +401,22 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
if(low != nullptr || high != nullptr){
|
||||
buildRangeInfo(nextNode, name);
|
||||
if(!name.empty()){
|
||||
_ranges->insert(name, low, high);
|
||||
buildRangeInfo(nextNode, enumCollVar, attr);
|
||||
if(!enumCollVar.empty()){
|
||||
_ranges->insert(enumCollVar, attr.substr(0, attr.size()-1), low, high);
|
||||
}
|
||||
}
|
||||
std::cout << _ranges->toString() << "\n";
|
||||
//std::cout << _ranges->toString() << "\n";
|
||||
}
|
||||
|
||||
if(node->type == NODE_TYPE_OPERATOR_BINARY_AND){
|
||||
buildRangeInfo(node->getMember(0), name);
|
||||
buildRangeInfo(node->getMember(1), name);
|
||||
std::cout << _ranges->toString() << "\n";
|
||||
attr = "";
|
||||
buildRangeInfo(node->getMember(0), enumCollVar, attr);
|
||||
attr = "";
|
||||
buildRangeInfo(node->getMember(1), enumCollVar, attr);
|
||||
//std::cout << _ranges->toString() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -380,7 +427,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
|||
ExecutionPlan* plan,
|
||||
Optimizer::PlanList& out,
|
||||
bool& keep) {
|
||||
|
||||
keep = true;
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||
|
||||
|
@ -388,7 +435,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
|||
auto nn = static_cast<FilterNode*>(n);
|
||||
auto invars = nn->getVariablesUsedHere();
|
||||
TRI_ASSERT(invars.size() == 1);
|
||||
CalculationNodeFinder finder(plan, invars[0]);
|
||||
CalculationNodeFinder finder(plan, invars[0], out);
|
||||
nn->walk(&finder);
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ QueryResult Query::execute () {
|
|||
opt.createPlans(plan); // Now plan and all derived plans belong to the
|
||||
// optimizer
|
||||
plan = opt.stealBest(); // Now we own the best one again
|
||||
|
||||
TRI_ASSERT(plan != nullptr);
|
||||
triagens::basics::Json json(triagens::basics::Json::List);
|
||||
triagens::basics::Json stats;
|
||||
|
||||
|
|
Loading…
Reference in New Issue