1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

Conflicts:
	arangod/Aql/OptimizerRules.cpp
This commit is contained in:
Max Neunhoeffer 2014-08-29 15:51:08 +02:00
commit 4ae076db40
8 changed files with 226 additions and 123 deletions

View File

@ -32,6 +32,7 @@
#include "Aql/AstNode.h"
#include "Aql/ExecutionNode.h"
#include "Aql/Expression.h"
#include "Aql/Optimizer.h"
#include "Aql/Query.h"
#include "Aql/Variable.h"
#include "Aql/WalkerWorker.h"
@ -116,6 +117,33 @@ ExecutionPlan* ExecutionPlan::instanciateFromJson (Ast* ast,
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief export to JSON, returns an AUTOFREE Json object
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json ExecutionPlan::toJson (TRI_memory_zone_t* zone,
bool verbose) const {
triagens::basics::Json result = _root->toJson(zone, verbose);
// set up rules
triagens::basics::Json rules(Json::List);
auto const&& appliedRules = Optimizer::translateRules(_appliedRules);
for (auto r : appliedRules) {
rules.add(Json(r));
}
result.set("rules", rules);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get a list of all applied rules
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> ExecutionPlan::getAppliedRules () const {
return Optimizer::translateRules(_appliedRules);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get a node by its id
////////////////////////////////////////////////////////////////////////////////
@ -1122,11 +1150,12 @@ class CloneNodeAdder : public WalkerWorker<ExecutionNode> {
}
};
ExecutionPlan* ExecutionPlan::clone (){
ExecutionPlan* ExecutionPlan::clone () {
auto plan = new ExecutionPlan();
try {
plan->_root = _root->clone();
plan->_nextId = _nextId;
plan->_appliedRules = _appliedRules;
CloneNodeAdder adder(plan);
plan->_root->walk(&adder);
if (! adder.success) {

View File

@ -31,9 +31,10 @@
#define ARANGODB_AQL_EXECUTION_PLAN_H 1
#include "Basics/Common.h"
#include "arangod/Aql/ExecutionNode.h"
#include "arangod/Aql/ModificationOptions.h"
#include "arangod/Aql/Query.h"
#include "Aql/ExecutionNode.h"
#include "Aql/ModificationOptions.h"
#include "Aql/Query.h"
#include "BasicsC/json.h"
namespace triagens {
namespace aql {
@ -93,10 +94,22 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
triagens::basics::Json toJson (TRI_memory_zone_t* zone,
bool verbose) const {
return _root->toJson(zone, verbose);
bool verbose) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief note that an optimizer rule was applied
////////////////////////////////////////////////////////////////////////////////
inline void addAppliedRule (int level) {
_appliedRules.push_back(level);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get a list of all applied rules
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> getAppliedRules () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return the next value for a node id
////////////////////////////////////////////////////////////////////////////////
@ -375,6 +388,12 @@ namespace triagens {
std::unordered_map<VariableId, ExecutionNode*> _varSetBy;
////////////////////////////////////////////////////////////////////////////////
/// @brief which optimizer rules were applied for a plan
////////////////////////////////////////////////////////////////////////////////
std::vector<int> _appliedRules;
////////////////////////////////////////////////////////////////////////////////
/// @brief flag to indicate whether the variable usage is computed
////////////////////////////////////////////////////////////////////////////////

View File

@ -149,7 +149,6 @@ namespace triagens {
std::vector<Variable*> const&,
std::vector<RegisterId> const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether this is a simple expression.
////////////////////////////////////////////////////////////////////////////////

View File

@ -56,6 +56,29 @@ Optimizer::Optimizer () {
}
}
////////////////////////////////////////////////////////////////////////////////
// @brief add a plan to the optimizer
////////////////////////////////////////////////////////////////////////////////
bool Optimizer::addPlan (ExecutionPlan* plan,
int level,
bool wasModified) {
TRI_ASSERT(plan != nullptr);
_newPlans.push_back(plan, level);
if (wasModified) {
// register which rules modified / created the plan
plan->addAppliedRule(_currentRule);
}
if (_newPlans.size() > maxNumberOfPlans) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// @brief the actual optimization
////////////////////////////////////////////////////////////////////////////////
@ -75,15 +98,14 @@ int Optimizer::createPlans (ExecutionPlan* plan,
_plans.clear();
_plans.push_back(plan, 0);
_newPlans.clear();
// int pass = 1;
while (leastDoneLevel < maxRuleLevel) {
/*
std::cout << "Entering pass " << pass << " of query optimization..."
<< std::endl;
*/
// This vector holds the plans we have created in this pass:
PlanList newPlans;
// Find variable usage for all old plans now:
for (auto p : _plans.list) {
if (! p->varUsageComputed()) {
@ -106,7 +128,7 @@ int Optimizer::createPlans (ExecutionPlan* plan,
int level;
auto p = _plans.pop_front(level);
if (level == maxRuleLevel) {
newPlans.push_back(p, level); // nothing to do, just keep it
_newPlans.push_back(p, level); // nothing to do, just keep it
}
else { // find next rule
auto it = _rules.upper_bound(level);
@ -122,13 +144,15 @@ int Optimizer::createPlans (ExecutionPlan* plan,
// we picked a disabled rule
level = it->first;
newPlans.push_back(p, level); // nothing to do, just keep it
_newPlans.push_back(p, level); // nothing to do, just keep it
// now try next
continue;
}
_currentRule = it->second.level;
try {
res = it->second.func(this, p, it->first, newPlans);
res = it->second.func(this, p, &(it->second));
}
catch (...) {
delete p;
@ -144,7 +168,7 @@ int Optimizer::createPlans (ExecutionPlan* plan,
// a good-enough plan is probably every plan with costs below some
// defined threshold. this requires plan costs to be calculated here
}
_plans.steal(newPlans);
_plans.steal(_newPlans);
leastDoneLevel = maxRuleLevel;
for (auto l : _plans.levelDone) {
if (l < leastDoneLevel) {
@ -159,6 +183,8 @@ int Optimizer::createPlans (ExecutionPlan* plan,
}
}
TRI_ASSERT(_plans.size() >= 1);
estimatePlans();
sortPlans();
/*
@ -174,6 +200,26 @@ int Optimizer::createPlans (ExecutionPlan* plan,
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief translate a list of rule ids into rule name
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> Optimizer::translateRules (std::vector<int> const& rules) {
std::vector<std::string> names;
for (auto r : rules) {
auto it = _rules.find(r);
if (it != _rules.end()) {
names.emplace_back((*it).second.name);
}
}
return names;
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief estimatePlans
////////////////////////////////////////////////////////////////////////////////

View File

@ -40,8 +40,40 @@ namespace triagens {
// -----------------------------------------------------------------------------
class Optimizer {
public:
struct Rule;
////////////////////////////////////////////////////////////////////////////////
/// @brief type of an optimizer rule function, the function gets an
/// optimiser, an ExecutionPlan, and the current rule. it has
/// to append one or more plans to the resulting deque. This must
/// include the original plan if it ought to be kept. The rule has to
/// set the level of the appended plan to the largest level of rule
/// that ought to be considered as done to indicate which rule is to be
/// applied next.
////////////////////////////////////////////////////////////////////////////////
typedef std::function<int(Optimizer*, ExecutionPlan*, Rule const*)> RuleFunction;
////////////////////////////////////////////////////////////////////////////////
/// @brief type of an optimizer rule
////////////////////////////////////////////////////////////////////////////////
struct Rule {
std::string name;
RuleFunction func;
int level;
Rule () = delete;
Rule (std::string const& name, RuleFunction func, int level)
: name(name),
func(func),
level(level) {
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief the following struct keeps a list (deque) of ExecutionPlan*
@ -167,38 +199,6 @@ namespace triagens {
};
////////////////////////////////////////////////////////////////////////////////
/// @brief type of an optimizer rule function, the function gets an
/// optimiser, an ExecutionPlan, the current level of this rule and
/// has to append one or more plans to the resulting deque. This must
/// include the original plan if it ought to be kept. The rule has to
/// set the level of the appended plan to the largest level of rule
/// that ought to be considered as done to indicate which rule is to be
/// applied next.
////////////////////////////////////////////////////////////////////////////////
typedef std::function<int(Optimizer* opt,
ExecutionPlan* plan,
int level,
PlanList& out)>
RuleFunction;
////////////////////////////////////////////////////////////////////////////////
/// @brief type of an optimizer rule
////////////////////////////////////////////////////////////////////////////////
struct Rule {
std::string name;
RuleFunction func;
int level;
Rule (std::string const& name, RuleFunction f, int l)
: name(name),
func(f),
level(l) {
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief maximal number of plans to produce:
////////////////////////////////////////////////////////////////////////////////
@ -233,6 +233,15 @@ namespace triagens {
int createPlans (ExecutionPlan* p,
std::vector<std::string> const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief add a plan to the optimizer
/// returns false if there are already enough plans, true otherwise
////////////////////////////////////////////////////////////////////////////////
bool addPlan (ExecutionPlan*,
int,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief getBest, ownership of the plan remains with the optimizer
////////////////////////////////////////////////////////////////////////////////
@ -268,7 +277,6 @@ namespace triagens {
_plans.list.clear();
_plans.levelDone.clear();
// std::cout << res->toJson(TRI_UNKNOWN_MEM_ZONE, false).toString() << "\n";
return res;
}
@ -284,6 +292,12 @@ namespace triagens {
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief translate a list of rule ids into rule name
////////////////////////////////////////////////////////////////////////////////
static std::vector<std::string> translateRules (std::vector<int> const&);
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
@ -313,7 +327,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
static void registerRule (std::string const& name,
RuleFunction f,
RuleFunction func,
int level) {
if (_ruleLookup.find(name) != _ruleLookup.end()) {
// duplicate rule names are not allowed
@ -326,7 +340,7 @@ namespace triagens {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "duplicate optimizer rule level");
}
_rules.insert(std::make_pair(level, Rule(name, f, level)));
_rules.insert(std::make_pair(level, Rule(name, func, level)));
}
////////////////////////////////////////////////////////////////////////////////
@ -359,6 +373,18 @@ namespace triagens {
PlanList _plans;
////////////////////////////////////////////////////////////////////////////////
/// @brief current list of plans (while applying optimizer rules)
////////////////////////////////////////////////////////////////////////////////
PlanList _newPlans;
////////////////////////////////////////////////////////////////////////////////
/// @brief currently active rule (during optimization)
////////////////////////////////////////////////////////////////////////////////
int _currentRule;
};
} // namespace aql

View File

@ -45,9 +45,8 @@ using EN = triagens::aql::ExecutionNode;
////////////////////////////////////////////////////////////////////////////////
int triagens::aql::removeRedundantSorts (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
ExecutionPlan* plan,
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::SORT, true);
std::unordered_set<ExecutionNode*> toUnlink;
@ -97,7 +96,7 @@ int triagens::aql::removeRedundantSorts (Optimizer* opt,
plan->findVarUsage();
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, ! toUnlink.empty());
return TRI_ERROR_NO_ERROR;
}
@ -111,8 +110,8 @@ int triagens::aql::removeRedundantSorts (Optimizer* opt,
int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
bool modified = false;
std::unordered_set<ExecutionNode*> toUnlink;
// should we enter subqueries??
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
@ -149,6 +148,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
// filter is always true
// remove filter node and merge with following node
toUnlink.insert(n);
modified = true;
}
else {
// filter is always false
@ -156,6 +156,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
auto noResults = new NoResultsNode(plan->nextId());
plan->registerNode(noResults);
plan->replaceNode(n, noResults);
modified = true;
}
}
@ -164,7 +165,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
plan->findVarUsage();
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, modified);
return TRI_ERROR_NO_ERROR;
}
@ -178,8 +179,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
bool modified = false;
@ -243,7 +243,7 @@ int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
plan->findVarUsage();
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, modified);
return TRI_ERROR_NO_ERROR;
}
@ -258,8 +258,7 @@ int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
int triagens::aql::moveFiltersUpRule (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
bool modified = false;
@ -323,7 +322,7 @@ int triagens::aql::moveFiltersUpRule (Optimizer* opt,
plan->findVarUsage();
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, modified);
return TRI_ERROR_NO_ERROR;
}
@ -335,8 +334,7 @@ int triagens::aql::moveFiltersUpRule (Optimizer* opt,
int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
std::unordered_set<ExecutionNode*> toUnlink;
@ -366,7 +364,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
plan->findVarUsage();
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, ! toUnlink.empty());
return TRI_ERROR_NO_ERROR;
}
@ -376,20 +374,19 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
////////////////////////////////////////////////////////////////////////////////
class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
RangesInfo* _ranges;
RangesInfo* _ranges;
Optimizer* _opt;
ExecutionPlan* _plan;
std::unordered_set<VariableId> _varIds;
Optimizer::PlanList* _out;
bool _canThrow;
int _level;
public:
FilterToEnumCollFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList* out, int level)
: _plan(plan),
_out(out),
_canThrow(false),
_level(level) {
FilterToEnumCollFinder (Optimizer* opt, ExecutionPlan* plan, Variable const* var)
: _opt(opt),
_plan(plan),
_canThrow(false) {
_ranges = new RangesInfo();
_varIds.insert(var->id);
};
@ -416,7 +413,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
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.empty()) {
if (! map.empty()) {
// check the first components of <map> against indexes of <node> . . .
std::unordered_set<std::string> attrs;
@ -433,7 +430,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
}
if (! _canThrow) {
if (! valid){ // ranges are not valid . . .
if (! valid) { // ranges are not valid . . .
auto newPlan = _plan->clone();
try {
@ -442,7 +439,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
auto noRes = new NoResultsNode(newPlan->nextId());
newPlan->registerNode(noRes);
newPlan->insertDependency(x, noRes);
_out->push_back(newPlan, 0);
_opt->addPlan(newPlan, _level, true);
}
}
catch (...) {
@ -495,7 +492,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
node->collection(), node->outVariable(), idx, rangeInfo);
newPlan->registerNode(newNode);
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
_out->push_back(newPlan, _level);
_opt->addPlan(newPlan, _level, true);
}
catch (...) {
delete newPlan;
@ -625,9 +622,8 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
int triagens::aql::useIndexRange (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
out.push_back(plan, level);
Optimizer::Rule const* rule) {
opt->addPlan(plan, rule->level, false);
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
@ -636,19 +632,18 @@ int triagens::aql::useIndexRange (Optimizer* opt,
auto nn = static_cast<FilterNode*>(n);
auto invars = nn->getVariablesUsedHere();
TRI_ASSERT(invars.size() == 1);
FilterToEnumCollFinder finder(plan, invars[0], &out, level);
FilterToEnumCollFinder finder(opt, plan, invars[0]);
nn->walk(&finder);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief analyse the sortnode and its calculation nodes
////////////////////////////////////////////////////////////////////////////////
class sortAnalysis
{
class sortAnalysis {
using ECN = triagens::aql::EnumerateCollectionNode;
typedef std::pair<ECN::IndexMatchVec, RangeInfoVec> Range_IndexPair;
@ -773,18 +768,18 @@ public:
class sortToIndexNode : public WalkerWorker<ExecutionNode> {
using ECN = triagens::aql::EnumerateCollectionNode;
Optimizer* _opt;
ExecutionPlan* _plan;
Optimizer::PlanList& _out;
sortAnalysis* _sortNode;
int _level;
public:
sortToIndexNode (ExecutionPlan* plan,
Optimizer::PlanList& out,
sortToIndexNode (Optimizer* opt,
ExecutionPlan* plan,
sortAnalysis* Node,
int level)
: _plan(plan),
_out(out),
: _opt(opt),
_plan(plan),
_sortNode(Node),
_level(level) {
}
@ -792,12 +787,13 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
////////////////////////////////////////////////////////////////////////////////
/// @brief if the sort is already done by an indexrange, remove the sort.
////////////////////////////////////////////////////////////////////////////////
bool handleIndexRangeNode(IndexRangeNode* node) {
auto variableName = node->getVariablesSetHere()[0]->name;
auto result = _sortNode->getAttrsForVariableName(variableName);
if (node->MatchesIndex(result.first)) {
_sortNode->removeSortNodeFromPlan(_plan);
_sortNode->removeSortNodeFromPlan(_plan);
}
return true;
}
@ -805,8 +801,8 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether we can sort via an index.
////////////////////////////////////////////////////////////////////////////////
bool handleEnumerateCollectionNode(EnumerateCollectionNode* node, int level)
{
bool handleEnumerateCollectionNode(EnumerateCollectionNode* node, int level) {
auto variableName = node->getVariablesSetHere()[0]->name;
auto result = _sortNode->getAttrsForVariableName(variableName);
@ -834,7 +830,7 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
if (idx.fullmatch) { // if the index superseedes the sort, remove it.
_sortNode->removeSortNodeFromPlan(newPlan);
}
_out.push_back(newPlan, level);
_opt->addPlan(newPlan, level, true);
}
catch (...) {
delete newPlan;
@ -842,11 +838,7 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
}
}
/*for (auto x : result.second) {
for (auto y : x) {
delete y;
}
}*/
return true;
}
@ -896,20 +888,19 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
int triagens::aql::useIndexForSort (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::SORT, true);
for (auto n : nodes) {
auto thisSortNode = static_cast<SortNode*>(n);
sortAnalysis node(thisSortNode);
if (node.isAnalyzeable()) {
sortToIndexNode finder(plan, out, &node, level);
sortToIndexNode finder(opt, plan, &node, rule->level);
thisSortNode->walk(&finder);/// todo auf der dependency anfangen
}
}
out.push_back(plan, level);
opt->addPlan(plan, rule->level, false);
return TRI_ERROR_NO_ERROR;
}
@ -954,9 +945,7 @@ static bool nextPermutationTuple (std::vector<size_t>& data,
int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out) {
Optimizer::Rule const* rule) {
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::ENUMERATE_COLLECTION,
true);
@ -1009,7 +998,8 @@ int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
// plan, we need to compute all possible permutations of all of them,
// independently. This is why we need to compute all permutation tuples.
out.push_back(plan, level);
opt->addPlan(plan, rule->level, false);
if (! starts.empty()) {
nextPermutationTuple(permTuple, starts); // will never return false
do {
@ -1050,10 +1040,7 @@ int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
}
// OK, the new plan is ready, let's report it:
out.push_back(newPlan, level);
// Stop if this gets out of hand:
if (out.size() > opt->maxNumberOfPlans) {
if (! opt->addPlan(newPlan, rule->level, true)) {
break;
}
}

View File

@ -46,7 +46,7 @@ namespace triagens {
/// - sorts that are covered by earlier sorts will be removed
////////////////////////////////////////////////////////////////////////////////
int removeRedundantSorts (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int removeRedundantSorts (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief remove all unnecessary filters
@ -55,7 +55,7 @@ namespace triagens {
/// - filters that are always false will be replaced by a NoResults node
////////////////////////////////////////////////////////////////////////////////
int removeUnnecessaryFiltersRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int removeUnnecessaryFiltersRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief move calculations up in the plan
@ -64,7 +64,7 @@ namespace triagens {
/// avoid redundant calculations in inner loops
////////////////////////////////////////////////////////////////////////////////
int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief move filters up in the plan
@ -74,34 +74,31 @@ namespace triagens {
/// filters are not pushed beyond limits
////////////////////////////////////////////////////////////////////////////////
int moveFiltersUpRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int moveFiltersUpRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a CalculationNode that is never needed
////////////////////////////////////////////////////////////////////////////////
int removeUnnecessaryCalculationsRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int removeUnnecessaryCalculationsRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief prefer IndexRange nodes over EnumerateCollection nodes
////////////////////////////////////////////////////////////////////////////////
int useIndexRange (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int useIndexRange (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief try to use the index for sorting
////////////////////////////////////////////////////////////////////////////////
int useIndexForSort (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
int useIndexForSort (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief interchange adjacent EnumerateCollectionNodes in all possible ways
////////////////////////////////////////////////////////////////////////////////
int interchangeAdjacentEnumerations ( Optimizer* opt,
ExecutionPlan* plan,
int level,
Optimizer::PlanList& out);
int interchangeAdjacentEnumerations (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
} // namespace aql
} // namespace triagens

View File

@ -375,10 +375,10 @@ QueryResult Query::explain () {
TRI_ASSERT(plan != nullptr);
trx.commit();
//triagens::basic::Json json(triagens::basic::Json::Array);
QueryResult result(TRI_ERROR_NO_ERROR);
result.json = plan->toJson(TRI_UNKNOWN_MEM_ZONE, false).steal(); //json();
delete plan;
return result;