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
|
// Now put info about vocbase and cid in there
|
||||||
json("database", Json(_vocbase->_name))
|
/*json("database", Json(_vocbase->_name))
|
||||||
("collection", Json(_collection->name))
|
("collection", Json(_collection->name))
|
||||||
("outVariable", _outVariable->toJson())
|
("outVariable", _outVariable->toJson())
|
||||||
("index", _index->index()->json(_index->index()))
|
("index", _index->index()->json(_index->index()))
|
||||||
("ranges", ranges);
|
("ranges", ranges);*/
|
||||||
|
|
||||||
// And add it:
|
// And add it:
|
||||||
nodes(json);
|
nodes(json);
|
||||||
|
|
|
@ -178,6 +178,24 @@ namespace triagens {
|
||||||
return _dependencies;
|
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
|
/// @brief remove a dependency, returns true if the pointer was found and
|
||||||
/// removed, please note that this does not delete ep!
|
/// removed, please note that this does not delete ep!
|
||||||
|
@ -545,6 +563,56 @@ namespace triagens {
|
||||||
return v;
|
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
|
// --SECTION-- private variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -798,28 +866,46 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
||||||
|
|
||||||
~RangesInfo(){}
|
~RangesInfo(){}
|
||||||
|
|
||||||
RangeInfo* find(std::string name) const {
|
RangeInfo* find(std::string var, std::string name) const {
|
||||||
auto it = _ranges.find(name);
|
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()) {
|
if (it == _ranges.end()) {
|
||||||
return nullptr;
|
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) {
|
void insert (std::string var, std::string name,
|
||||||
if( find(name) == nullptr ){
|
RangeInfoBound* low, RangeInfoBound* high) {
|
||||||
_ranges.insert(make_pair(name, range));
|
auto oldMap = find(var);
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void insert (std::string name, RangeInfoBound* low, RangeInfoBound* high){
|
|
||||||
auto oldRange = find(name);
|
|
||||||
auto newRange = new RangeInfo(low, high);
|
auto newRange = new RangeInfo(low, high);
|
||||||
int cmp;
|
|
||||||
|
if (oldMap == nullptr) {
|
||||||
|
// TODO add exception . . .
|
||||||
|
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) {
|
if (oldRange == nullptr) {
|
||||||
// TODO add exception . . .
|
// TODO add exception . . .
|
||||||
_ranges.insert(make_pair(name, newRange));
|
oldMap->insert(make_pair(name, newRange));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,7 +923,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
||||||
|
|
||||||
// check the new range bounds are valid
|
// check the new range bounds are valid
|
||||||
if( oldRange->_low != nullptr && oldRange->_high != nullptr){
|
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());
|
oldRange->_high->_bound.json());
|
||||||
if (cmp == 1 || (cmp == 0 &&
|
if (cmp == 1 || (cmp == 0 &&
|
||||||
!(oldRange->_low->_include == true && oldRange->_high->_include == true ))){
|
!(oldRange->_low->_include == true && oldRange->_high->_include == true ))){
|
||||||
|
@ -852,7 +938,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
||||||
return _ranges.size();
|
return _ranges.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Json toJson () const {
|
/*Json toJson () const {
|
||||||
Json list(Json::List);
|
Json list(Json::List);
|
||||||
for (auto x : _ranges) {
|
for (auto x : _ranges) {
|
||||||
Json item(Json::Array);
|
Json item(Json::Array);
|
||||||
|
@ -865,10 +951,10 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
return this->toJson().toString();
|
return this->toJson().toString();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private:
|
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,
|
TRI_vocbase_t* vocbase,
|
||||||
Collection* collection,
|
Collection* collection,
|
||||||
Variable const* outVariable,
|
Variable const* outVariable,
|
||||||
Index* index,
|
TRI_index_t* index,
|
||||||
vector<RangeInfo*>* ranges)
|
vector<RangeInfo*>* ranges)
|
||||||
: ExecutionNode(id),
|
: ExecutionNode(id),
|
||||||
_vocbase(vocbase),
|
_vocbase(vocbase),
|
||||||
|
@ -984,7 +1070,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
|
||||||
/// @brief the index
|
/// @brief the index
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Index* _index;
|
TRI_index_t* _index;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief the range info
|
/// @brief the range info
|
||||||
|
|
|
@ -51,12 +51,10 @@ using JsonHelper = triagens::basics::JsonHelper;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ExecutionPlan::ExecutionPlan ()
|
ExecutionPlan::ExecutionPlan ()
|
||||||
: _nodes(),
|
: _ids(),
|
||||||
_ids(),
|
|
||||||
_root(nullptr),
|
_root(nullptr),
|
||||||
_nextId(0) {
|
_nextId(0) {
|
||||||
|
|
||||||
_nodes.reserve(8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -64,8 +62,8 @@ ExecutionPlan::ExecutionPlan ()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ExecutionPlan::~ExecutionPlan () {
|
ExecutionPlan::~ExecutionPlan () {
|
||||||
for (auto it = _nodes.begin(); it != _nodes.end(); ++it) {
|
for (auto x : _ids){
|
||||||
delete (*it);
|
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 != nullptr);
|
||||||
TRI_ASSERT(node->id() > 0);
|
TRI_ASSERT(node->id() > 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_nodes.push_back(node);
|
|
||||||
_ids.insert(std::make_pair(node->id(), node));
|
_ids.insert(std::make_pair(node->id(), node));
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
delete node;
|
delete node;
|
||||||
throw;
|
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 {
|
try {
|
||||||
auto en = new CalculationNode(nextId(), expr, out);
|
auto en = new CalculationNode(nextId(), expr, out);
|
||||||
|
|
||||||
addNode(reinterpret_cast<ExecutionNode*>(en));
|
registerNode(reinterpret_cast<ExecutionNode*>(en));
|
||||||
return en;
|
return en;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// prevent memleak
|
// prevent memleak
|
||||||
delete expr;
|
delete expr;
|
||||||
|
@ -285,20 +297,20 @@ ExecutionNode* ExecutionPlan::fromNodeFor (Ast const* ast,
|
||||||
if (collection == nullptr) {
|
if (collection == nullptr) {
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "no collection for EnumerateCollection");
|
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) {
|
else if (expression->type == NODE_TYPE_REFERENCE) {
|
||||||
// second operand is already a variable
|
// second operand is already a variable
|
||||||
auto inVariable = static_cast<Variable*>(expression->getData());
|
auto inVariable = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(inVariable != nullptr);
|
TRI_ASSERT(inVariable != nullptr);
|
||||||
en = addNode(new EnumerateListNode(nextId(), inVariable, v));
|
en = registerNode(new EnumerateListNode(nextId(), inVariable, v));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// second operand is some misc. expression
|
// second operand is some misc. expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
|
|
||||||
calc->addDependency(previous);
|
calc->addDependency(previous);
|
||||||
en = addNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
|
en = registerNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,14 +337,14 @@ ExecutionNode* ExecutionPlan::fromNodeFilter (Ast const* ast,
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
TRI_ASSERT(v != nullptr);
|
||||||
en = addNode(new FilterNode(nextId(), v));
|
en = registerNode(new FilterNode(nextId(), v));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
|
|
||||||
calc->addDependency(previous);
|
calc->addDependency(previous);
|
||||||
en = addNode(new FilterNode(nextId(), calc->outVariable()));
|
en = registerNode(new FilterNode(nextId(), calc->outVariable()));
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,14 +378,14 @@ ExecutionNode* ExecutionPlan::fromNodeLet (Ast const* ast,
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
en = addNode(new SubqueryNode(nextId(), subquery, v));
|
en = registerNode(new SubqueryNode(nextId(), subquery, v));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// operand is some misc expression, including references to other variables
|
// operand is some misc expression, including references to other variables
|
||||||
auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression));
|
auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
en = addNode(new CalculationNode(nextId(), expr, v));
|
en = registerNode(new CalculationNode(nextId(), expr, v));
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// prevent memleak
|
// prevent memleak
|
||||||
|
@ -441,7 +453,7 @@ ExecutionNode* ExecutionPlan::fromNodeSort (Ast const* ast,
|
||||||
previous = (*it);
|
previous = (*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto en = addNode(new SortNode(nextId(), elements));
|
auto en = registerNode(new SortNode(nextId(), elements));
|
||||||
|
|
||||||
return addDependency(previous, en);
|
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...
|
// 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);
|
sort->addDependency(previous);
|
||||||
previous = sort;
|
previous = sort;
|
||||||
|
|
||||||
|
@ -514,7 +526,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
|
||||||
outVariable = static_cast<Variable*>(v->getData());
|
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);
|
return addDependency(previous, en);
|
||||||
}
|
}
|
||||||
|
@ -535,7 +547,7 @@ ExecutionNode* ExecutionPlan::fromNodeLimit (Ast const* ast,
|
||||||
TRI_ASSERT(offset->type == NODE_TYPE_VALUE);
|
TRI_ASSERT(offset->type == NODE_TYPE_VALUE);
|
||||||
TRI_ASSERT(count->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);
|
return addDependency(previous, en);
|
||||||
}
|
}
|
||||||
|
@ -558,13 +570,13 @@ ExecutionNode* ExecutionPlan::fromNodeReturn (Ast const* ast,
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
TRI_ASSERT(v != nullptr);
|
||||||
en = addNode(new ReturnNode(nextId(), v));
|
en = registerNode(new ReturnNode(nextId(), v));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
calc->addDependency(previous);
|
calc->addDependency(previous);
|
||||||
en = addNode(new ReturnNode(nextId(), calc->outVariable()));
|
en = registerNode(new ReturnNode(nextId(), calc->outVariable()));
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,13 +609,13 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
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 {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
calc->addDependency(previous);
|
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;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,13 +643,13 @@ ExecutionNode* ExecutionPlan::fromNodeInsert (Ast const* ast,
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(expression->getData());
|
auto v = static_cast<Variable*>(expression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
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 {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, expression);
|
auto calc = createTemporaryCalculation(ast, expression);
|
||||||
calc->addDependency(previous);
|
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;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,13 +695,13 @@ ExecutionNode* ExecutionPlan::fromNodeUpdate (Ast const* ast,
|
||||||
// document operand is already a variable
|
// document operand is already a variable
|
||||||
auto v = static_cast<Variable*>(docExpression->getData());
|
auto v = static_cast<Variable*>(docExpression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
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 {
|
else {
|
||||||
// document operand is some misc expression
|
// document operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, docExpression);
|
auto calc = createTemporaryCalculation(ast, docExpression);
|
||||||
calc->addDependency(previous);
|
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;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,13 +747,13 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
|
||||||
// operand is already a variable
|
// operand is already a variable
|
||||||
auto v = static_cast<Variable*>(docExpression->getData());
|
auto v = static_cast<Variable*>(docExpression->getData());
|
||||||
TRI_ASSERT(v != nullptr);
|
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 {
|
else {
|
||||||
// operand is some misc expression
|
// operand is some misc expression
|
||||||
auto calc = createTemporaryCalculation(ast, docExpression);
|
auto calc = createTemporaryCalculation(ast, docExpression);
|
||||||
calc->addDependency(previous);
|
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;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,7 +768,7 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
|
||||||
AstNode const* node) {
|
AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr);
|
TRI_ASSERT(node != nullptr);
|
||||||
|
|
||||||
ExecutionNode* en = addNode(new SingletonNode(nextId()));
|
ExecutionNode* en = registerNode(new SingletonNode(nextId()));
|
||||||
|
|
||||||
size_t const n = node->numMembers();
|
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> {
|
struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
||||||
|
@ -963,6 +975,7 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto dep = en->getDependencies();
|
auto dep = en->getDependencies();
|
||||||
|
//TODO make exception safe
|
||||||
parents.back()->removeDependency(en);
|
parents.back()->removeDependency(en);
|
||||||
if (dep.size() == 1) {
|
if (dep.size() == 1) {
|
||||||
parents.back()->addDependency(dep[0]);
|
parents.back()->addDependency(dep[0]);
|
||||||
|
@ -977,29 +990,87 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void after (ExecutionNode* en) {
|
void after (ExecutionNode* en) {
|
||||||
|
_plan->unregisterNode(en);
|
||||||
parents.pop_back();
|
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.
|
/// 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);
|
NodeRemover remover(this, toRemove);
|
||||||
root()->walk(&remover);
|
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.
|
/// node and that one cannot remove the root node of the plan.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ExecutionPlan::removeNode (ExecutionNode* node) {
|
void ExecutionPlan::unlinkNode (ExecutionNode* node) {
|
||||||
std::unordered_set<ExecutionNode*> toRemove;
|
std::unordered_set<ExecutionNode*> toUnlink;
|
||||||
toRemove.insert(node);
|
toUnlink.insert(node);
|
||||||
return removeNodes(toRemove);
|
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,
|
ret = ExecutionNode::fromJsonFactory(ast,
|
||||||
oneJsonNode);
|
oneJsonNode);
|
||||||
|
|
||||||
addNode(ret);
|
registerNode(ret);
|
||||||
|
|
||||||
TRI_ASSERT(ret != nullptr);
|
TRI_ASSERT(ret != nullptr);
|
||||||
|
|
||||||
|
|
|
@ -146,18 +146,43 @@ namespace triagens {
|
||||||
void findVarUsage ();
|
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.
|
/// 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.
|
/// 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
|
// --SECTION-- private methods
|
||||||
|
@ -171,11 +196,6 @@ namespace triagens {
|
||||||
|
|
||||||
ModificationOptions createOptions (AstNode const*);
|
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
|
/// @brief creates a calculation node for an arbitrary expression
|
||||||
|
@ -295,12 +315,6 @@ namespace triagens {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief all nodes registered, used for memory management
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::vector<ExecutionNode*> _nodes;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief map from node id to the actual node
|
/// @brief map from node id to the actual node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -79,8 +79,6 @@ namespace triagens {
|
||||||
return this->index()->_type;
|
return this->index()->_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// anything else??
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public variables
|
// --SECTION-- public variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -42,7 +42,7 @@ Optimizer::Optimizer () {
|
||||||
// List all the rules in the system here:
|
// List all the rules in the system here:
|
||||||
|
|
||||||
// try to find a filter after an enumerate collection and find an index . . .
|
// 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
|
// remove filters from the query that are not necessary at all
|
||||||
// filters that are always true will be removed entirely
|
// filters that are always true will be removed entirely
|
||||||
|
|
|
@ -50,7 +50,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
||||||
bool& keep) {
|
bool& keep) {
|
||||||
|
|
||||||
keep = true; // plan will always be kept
|
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);
|
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||||
|
|
||||||
for (auto n : nodes) {
|
for (auto n : nodes) {
|
||||||
|
@ -84,21 +84,20 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
||||||
if (root->toBoolean()) {
|
if (root->toBoolean()) {
|
||||||
// filter is always true
|
// filter is always true
|
||||||
// remove filter node and merge with following node
|
// remove filter node and merge with following node
|
||||||
toRemove.insert(n);
|
toUnlink.insert(n);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// filter is always false
|
// filter is always false
|
||||||
// TODO: insert a NoResults node below it
|
// TODO: insert a NoResults node below it
|
||||||
//auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId()));
|
//auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId()));
|
||||||
//TRI_ASSERT(noResultsNode != nullptr);
|
//TRI_ASSERT(noResultsNode != nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! toRemove.empty()) {
|
if (! toUnlink.empty()) {
|
||||||
std::cout << "Removing " << toRemove.size() << " unnecessary "
|
std::cout << "Removing " << toUnlink.size() << " unnecessary "
|
||||||
"nodes..." << std::endl;
|
"nodes..." << std::endl;
|
||||||
plan->removeNodes(toRemove);
|
plan->unlinkNodes(toUnlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
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
|
// no shared variables found. we can move the calculation up the dependency chain
|
||||||
|
|
||||||
// first, delete the calculation from the plan
|
// first, delete the calculation from the plan
|
||||||
plan->removeNode(n);
|
plan->unlinkNode(n);
|
||||||
|
|
||||||
// fiddle dependencies of calculation node
|
// fiddle dependencies of calculation node
|
||||||
n->removeDependencies();
|
n->removeDependencies();
|
||||||
|
@ -208,7 +207,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
||||||
keep = true;
|
keep = true;
|
||||||
std::vector<ExecutionNode*> nodes
|
std::vector<ExecutionNode*> nodes
|
||||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
|
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
|
||||||
std::unordered_set<ExecutionNode*> toRemove;
|
std::unordered_set<ExecutionNode*> toUnlink;
|
||||||
for (auto n : nodes) {
|
for (auto n : nodes) {
|
||||||
auto nn = static_cast<CalculationNode*>(n);
|
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
|
// The variable whose value is calculated here is not used at
|
||||||
// all further down the pipeline! We remove the whole
|
// all further down the pipeline! We remove the whole
|
||||||
// calculation node,
|
// calculation node,
|
||||||
toRemove.insert(n);
|
toUnlink.insert(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! toRemove.empty()) {
|
if (! toUnlink.empty()) {
|
||||||
std::cout << "Removing " << toRemove.size() << " unnecessary "
|
std::cout << "Removing " << toUnlink.size() << " unnecessary "
|
||||||
"CalculationNodes..." << std::endl;
|
"CalculationNodes..." << std::endl;
|
||||||
plan->removeNodes(toRemove);
|
plan->unlinkNodes(toUnlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
@ -246,10 +245,14 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
||||||
RangesInfo* _ranges;
|
RangesInfo* _ranges;
|
||||||
ExecutionPlan* _plan;
|
ExecutionPlan* _plan;
|
||||||
Variable const* _var;
|
Variable const* _var;
|
||||||
|
Optimizer::PlanList _out;
|
||||||
|
ExecutionNode* _prev;
|
||||||
|
|
||||||
|
//EnumerateCollectionNode const* _enumColl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var)
|
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out)
|
||||||
: _plan(plan), _var(var){
|
: _plan(plan), _var(var), _out(out), _prev(nullptr){
|
||||||
_ranges = new RangesInfo();
|
_ranges = new RangesInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,29 +262,73 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
||||||
TRI_ASSERT(outvar.size() == 1);
|
TRI_ASSERT(outvar.size() == 1);
|
||||||
if(outvar[0]->id == _var->id){
|
if(outvar[0]->id == _var->id){
|
||||||
auto node = static_cast<CalculationNode*>(en);
|
auto node = static_cast<CalculationNode*>(en);
|
||||||
std::string name;
|
std::string attr;
|
||||||
buildRangeInfo(node->expression()->node(), name);
|
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){
|
if(node->type == NODE_TYPE_REFERENCE){
|
||||||
auto var = static_cast<Variable*>(node->getData());
|
auto x = static_cast<Variable*>(node->getData());
|
||||||
auto setter = _plan->getVarSetBy(var->id);
|
auto setter = _plan->getVarSetBy(x->id);
|
||||||
if( setter != nullptr &&
|
if( setter != nullptr &&
|
||||||
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
|
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
|
||||||
name = var->name;
|
enumCollVar = x->name;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){
|
if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){
|
||||||
char const* attributeName = node->getStringValue();
|
char const* attributeName = node->getStringValue();
|
||||||
buildRangeInfo(node->getMember(0), name);
|
buildRangeInfo(node->getMember(0), enumCollVar, attr);
|
||||||
if(!name.empty()){
|
if(!enumCollVar.empty()){
|
||||||
name.push_back('.');
|
attr.append(attributeName);
|
||||||
name.append(attributeName);
|
attr.push_back('.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,14 +350,13 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(val != nullptr){
|
if(val != nullptr){
|
||||||
buildRangeInfo(nextNode, name);
|
buildRangeInfo(nextNode, enumCollVar, attr);
|
||||||
if(!name.empty()){
|
if(!enumCollVar.empty()){
|
||||||
_ranges->insert(name, new RangeInfoBound(val, true),
|
_ranges->insert(enumCollVar, attr.substr(0, attr.size()-1),
|
||||||
new RangeInfoBound(val, true));
|
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 ||
|
if(node->type == NODE_TYPE_OPERATOR_BINARY_LT ||
|
||||||
|
@ -355,21 +401,22 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(low != nullptr || high != nullptr){
|
if(low != nullptr || high != nullptr){
|
||||||
buildRangeInfo(nextNode, name);
|
buildRangeInfo(nextNode, enumCollVar, attr);
|
||||||
if(!name.empty()){
|
if(!enumCollVar.empty()){
|
||||||
_ranges->insert(name, low, high);
|
_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){
|
if(node->type == NODE_TYPE_OPERATOR_BINARY_AND){
|
||||||
buildRangeInfo(node->getMember(0), name);
|
attr = "";
|
||||||
buildRangeInfo(node->getMember(1), name);
|
buildRangeInfo(node->getMember(0), enumCollVar, attr);
|
||||||
std::cout << _ranges->toString() << "\n";
|
attr = "";
|
||||||
|
buildRangeInfo(node->getMember(1), enumCollVar, attr);
|
||||||
|
//std::cout << _ranges->toString() << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -380,7 +427,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
||||||
ExecutionPlan* plan,
|
ExecutionPlan* plan,
|
||||||
Optimizer::PlanList& out,
|
Optimizer::PlanList& out,
|
||||||
bool& keep) {
|
bool& keep) {
|
||||||
|
keep = true;
|
||||||
std::vector<ExecutionNode*> nodes
|
std::vector<ExecutionNode*> nodes
|
||||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||||
|
|
||||||
|
@ -388,7 +435,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
||||||
auto nn = static_cast<FilterNode*>(n);
|
auto nn = static_cast<FilterNode*>(n);
|
||||||
auto invars = nn->getVariablesUsedHere();
|
auto invars = nn->getVariablesUsedHere();
|
||||||
TRI_ASSERT(invars.size() == 1);
|
TRI_ASSERT(invars.size() == 1);
|
||||||
CalculationNodeFinder finder(plan, invars[0]);
|
CalculationNodeFinder finder(plan, invars[0], out);
|
||||||
nn->walk(&finder);
|
nn->walk(&finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ QueryResult Query::execute () {
|
||||||
opt.createPlans(plan); // Now plan and all derived plans belong to the
|
opt.createPlans(plan); // Now plan and all derived plans belong to the
|
||||||
// optimizer
|
// optimizer
|
||||||
plan = opt.stealBest(); // Now we own the best one again
|
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 json(triagens::basics::Json::List);
|
||||||
triagens::basics::Json stats;
|
triagens::basics::Json stats;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue