1
0
Fork 0
This commit is contained in:
Jan Steemann 2016-07-20 09:38:25 +02:00
parent f038fa386f
commit 8369f652a4
3 changed files with 86 additions and 5 deletions

View File

@ -1239,12 +1239,12 @@ class arangodb::aql::RedundantCalculationsReplacer final
public:
explicit RedundantCalculationsReplacer(
std::unordered_map<VariableId, Variable const*> const& replacements)
: _replacements(replacements) {}
: _replacements(replacements) {
}
template <typename T>
void replaceInVariable(ExecutionNode* en) {
auto node = static_cast<T*>(en);
node->_inVariable = Variable::replace(node->_inVariable, _replacements);
}
@ -1252,7 +1252,7 @@ class arangodb::aql::RedundantCalculationsReplacer final
auto node = static_cast<CalculationNode*>(en);
std::unordered_set<Variable const*> variables;
node->expression()->variables(variables);
// check if the calculation uses any of the variables that we want to
// replace
for (auto const& it : variables) {
@ -3784,6 +3784,14 @@ void arangodb::aql::inlineSubqueriesRule(Optimizer* opt,
auto queryVariables = plan->getAst()->variables();
std::vector<ExecutionNode*> subNodes(subqueryNode->getSubquery()->getDependencyChain(true));
// check if the subquery result variable is used after the FOR loop as well
std::unordered_set<Variable const*> varsUsedLater(listNode->getVarsUsedLater());
if (varsUsedLater.find(listNode->inVariable()) != varsUsedLater.end()) {
// exit the loop
current = nullptr;
break;
}
TRI_ASSERT(! subNodes.empty());
auto returnNode = static_cast<ReturnNode*>(subNodes[0]);
TRI_ASSERT(returnNode->getType() == EN::RETURN);

View File

@ -469,6 +469,12 @@ function removeClusterNodes (nodeTypes) {
});
}
function removeClusterNodesFromPlan (nodes) {
return nodes.filter(function (node) {
return ([ 'ScatterNode', 'GatherNode', 'DistributeNode', 'RemoteNode' ].indexOf(node.type) === -1);
});
}
exports.isEqual = isEqual;
exports.getParseResults = getParseResults;
exports.assertParseError = assertParseError;
@ -487,3 +493,4 @@ exports.findReferencedNodes = findReferencedNodes;
exports.getQueryMultiplePlansAndExecutions = getQueryMultiplePlansAndExecutions;
exports.removeAlwaysOnClusterRules = removeAlwaysOnClusterRules;
exports.removeClusterNodes = removeClusterNodes;
exports.removeClusterNodesFromPlan = removeClusterNodesFromPlan;

View File

@ -31,14 +31,14 @@
var jsunity = require("jsunity");
var helper = require("@arangodb/aql-helper");
var isEqual = helper.isEqual;
var db = require("@arangodb").db;
var ruleName = "inline-subqueries";
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function optimizerRuleTestSuite () {
var ruleName = "inline-subqueries";
// various choices to control the optimizer:
var paramNone = { optimizer: { rules: [ "-all" ] } };
var paramEnabled = { optimizer: { rules: [ "-all", "+" + ruleName ] }, inspectSimplePlans: true };
@ -161,8 +161,73 @@ function optimizerRuleTestSuite () {
result = AQL_EXECUTE(query[0]).json;
assertEqual(query[1], result, query);
});
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function optimizerRuleCollectionTestSuite () {
var c = null;
var cn = "UnitTestsOptimizer";
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
db._drop(cn);
c = db._create(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
db._drop(cn);
c = null;
},
testSpecificPlan1 : function () {
var query = "LET x = (FOR doc IN @@cn RETURN doc) FOR doc2 IN x RETURN doc2";
var result = AQL_EXPLAIN(query, { "@cn" : cn });
assertNotEqual(-1, result.plan.rules.indexOf(ruleName), query);
var nodes = helper.removeClusterNodesFromPlan(result.plan.nodes);
assertEqual(3, nodes.length);
assertEqual("ReturnNode", nodes[nodes.length - 1].type);
assertEqual("doc2", nodes[nodes.length - 1].inVariable.name);
assertEqual("EnumerateCollectionNode", nodes[nodes.length - 2].type);
assertEqual(cn, nodes[nodes.length - 2].collection);
},
testSpecificPlan2 : function () {
var query = "LET x = (FOR doc IN @@cn FILTER doc.foo == 'bar' RETURN doc) FOR doc2 IN x RETURN doc2";
var result = AQL_EXPLAIN(query, { "@cn" : cn });
assertNotEqual(-1, result.plan.rules.indexOf(ruleName), query);
var nodes = helper.removeClusterNodesFromPlan(result.plan.nodes);
assertEqual(5, nodes.length);
assertEqual("ReturnNode", nodes[nodes.length - 1].type);
assertEqual("doc2", nodes[nodes.length - 1].inVariable.name);
assertEqual("FilterNode", nodes[nodes.length - 2].type);
assertEqual("CalculationNode", nodes[nodes.length - 3].type);
assertEqual("EnumerateCollectionNode", nodes[nodes.length - 4].type);
assertEqual(cn, nodes[nodes.length - 4].collection);
},
testSpecificPlan3 : function () {
var query = "LET x = (FOR doc IN @@cn RETURN doc) FOR doc2 IN x RETURN x";
var result = AQL_EXPLAIN(query, { "@cn" : cn });
assertEqual(-1, result.plan.rules.indexOf(ruleName), query); // no optimization
}
};
}
@ -171,5 +236,6 @@ function optimizerRuleTestSuite () {
////////////////////////////////////////////////////////////////////////////////
jsunity.run(optimizerRuleTestSuite);
jsunity.run(optimizerRuleCollectionTestSuite);
return jsunity.done();