1
0
Fork 0

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

This commit is contained in:
Max Neunhoeffer 2014-09-12 11:22:28 +02:00
commit 46cb7304bf
3 changed files with 717 additions and 714 deletions

View File

@ -1215,7 +1215,7 @@ ExecutionNode* ExecutionPlan::fromJson (Ast* ast,
Json const& json) { Json const& json) {
ExecutionNode* ret = nullptr; ExecutionNode* ret = nullptr;
Json nodes = json.get("nodes"); Json nodes = json.get("nodes");
std::cout << nodes.toString() << "\n"; //std::cout << nodes.toString() << "\n";
if (! nodes.isList()) { if (! nodes.isList()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "nodes is not a list"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "nodes is not a list");

View File

@ -475,6 +475,30 @@ function findReferencedNodes(plan, testNode) {
return matches; return matches;
} }
function getQueryMultiplePlansAndExecutions (query, bindVars) {
var plan;
var i;
var plans = [];
var allPlans = [];
var results = [];
var paramNone = { optimizer: { rules: [ "-all" ]}, verbosePlans: true};
var paramAllPlans = { allPlans : true, verbosePlans: true};
// first fetch the unmodified version
plans [0] = AQL_EXPLAIN(query, bindVars, paramNone);
// then all of the ones permuted by by the optimizer.
allPlans = AQL_EXPLAIN(query, bindVars, paramAllPlans);
for (i=0; i < allPlans.plans.length; i++) {
plans[i+1] = {'plan':allPlans.plans[i]};
}
// Now execute each of these variations.
for (i=0; i < plans.length; i++) {
results += AQL_EXECUTEJSON(plans[i].plan, paramNone);
}
return {'plans': plans, 'results': results};
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- module exports // --SECTION-- module exports
@ -496,7 +520,7 @@ exports.getLinearizedPlan = getLinearizedPlan;
exports.getCompactPlan = getCompactPlan; exports.getCompactPlan = getCompactPlan;
exports.findExecutionNodes = findExecutionNodes; exports.findExecutionNodes = findExecutionNodes;
exports.findReferencedNodes = findReferencedNodes; exports.findReferencedNodes = findReferencedNodes;
exports.getQueryMultiplePlansAndExecutions = getQueryMultiplePlansAndExecutions;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -1,5 +1,4 @@
/*jslint indent: 2, nomen: true, maxlen: 200, sloppy: true, vars: true, white: true, plusplus: true */ /*global require, assertTrue, assertEqual, AQL_EXECUTE, AQL_EXPLAIN, loopmax */
/*global require, exports, assertTrue, assertEqual, AQL_EXECUTE, AQL_EXECUTEJSON, AQL_EXPLAIN, fail, loopmax */
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief tests for optimizer rules /// @brief tests for optimizer rules
@ -30,42 +29,14 @@
var PY = function (plan) { require("internal").print(require("js-yaml").safeDump(plan));}; var PY = function (plan) { require("internal").print(require("js-yaml").safeDump(plan));};
var internal = require("internal"); var internal = require("internal");
var jsunity = require("jsunity"); var jsunity = require("jsunity");
var errors = require("internal").errors;
var helper = require("org/arangodb/aql-helper"); var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2; // var getQueryResults = helper.getQueryResults2;
var assertQueryError = helper.assertQueryError2; // TODO! var assertQueryError = helper.assertQueryError2;
var isEqual = helper.isEqual; var isEqual = helper.isEqual;
var findExecutionNodes = helper.findExecutionNodes; var findExecutionNodes = helper.findExecutionNodes;
var findReferencedNodes = helper.findReferencedNodes; var findReferencedNodes = helper.findReferencedNodes;
//var getQueryMultiplePlansAndExecutions = helper.getQueryMultiplePlansAndExecutions; var getQueryMultiplePlansAndExecutions = helper.getQueryMultiplePlansAndExecutions;
function getQueryMultiplePlansAndExecutions (query, bindVars) {
var plan;
var i;
var plans = [];
var allPlans = [];
var results = [];
var paramNone = { optimizer: { rules: [ "-all" ]}, verbosePlans: true};
var paramAllPlans = { allPlans : true, verbosePlans: true};
PY(query);
// first fetch the unmodified version
plans [0] = AQL_EXPLAIN(query, bindVars, paramNone);
// then all of the ones permuted by by the optimizer.
allPlans = AQL_EXPLAIN(query, bindVars, paramAllPlans);
PY(allPlans.plans[0]);
for (i=0; i < allPlans.plans.length; i++) {
plans[i+1] = {'plan':allPlans.plans[i]};
}
// Now execute each of these variations.
for (i=0; i < plans.length; i++) {
PY(plans[i]);
results += AQL_EXECUTEJSON(plans[i].plan, {});
}
return {'plans': plans, 'results': results};
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test suite /// @brief test suite
@ -75,7 +46,6 @@ function optimizerRuleTestSuite() {
var ruleName = "use-index-for-sort"; var ruleName = "use-index-for-sort";
var secondRuleName = "use-index-range"; var secondRuleName = "use-index-range";
var removeCalculationNodes = "remove-unnecessary-calculations-2"; var removeCalculationNodes = "remove-unnecessary-calculations-2";
var thirdRuleName = "remove-redundant-sorts";
var colName = "UnitTestsAqlOptimizer" + ruleName.replace(/-/g, "_"); var colName = "UnitTestsAqlOptimizer" + ruleName.replace(/-/g, "_");
var colNameOther = colName + "_XX"; var colNameOther = colName + "_XX";
@ -83,11 +53,7 @@ function optimizerRuleTestSuite() {
var paramNone = { optimizer: { rules: [ "-all" ] } }; var paramNone = { optimizer: { rules: [ "-all" ] } };
var paramIndexFromSort = { optimizer: { rules: [ "-all", "+" + ruleName ] } }; var paramIndexFromSort = { optimizer: { rules: [ "-all", "+" + ruleName ] } };
var paramIndexRange = { optimizer: { rules: [ "-all", "+" + secondRuleName ] } }; var paramIndexRange = { optimizer: { rules: [ "-all", "+" + secondRuleName ] } };
var paramRedundantSort = { optimizer: { rules: [ "-all", "+" + thirdRuleName ] } };
var paramIndexFromSort_IndexRange = { optimizer: { rules: [ "-all", "+" + ruleName, "+" + secondRuleName ] } }; var paramIndexFromSort_IndexRange = { optimizer: { rules: [ "-all", "+" + ruleName, "+" + secondRuleName ] } };
var paramIndexRangeRemoveCalculations = {
optimizer: { rules: [ "-all", "+" + secondRuleName, "+" + removeCalculationNodes ] }
};
var paramIndexFromSort_IndexRange_RemoveCalculations = { var paramIndexFromSort_IndexRange_RemoveCalculations = {
optimizer: { rules: [ "-all", "+" + ruleName, "+" + secondRuleName, "+" + removeCalculationNodes ] } optimizer: { rules: [ "-all", "+" + ruleName, "+" + secondRuleName, "+" + removeCalculationNodes ] }
}; };
@ -129,11 +95,12 @@ function optimizerRuleTestSuite() {
var hasIndexRangeNode_WithRanges = function (plan, haveRanges) { var hasIndexRangeNode_WithRanges = function (plan, haveRanges) {
var rn = findExecutionNodes(plan, "IndexRangeNode"); var rn = findExecutionNodes(plan, "IndexRangeNode");
assertEqual(rn.length, 1, "Has IndexRangeNode"); assertEqual(rn.length, 1, "Has IndexRangeNode");
assertTrue(rn[0].ranges.length > 0, "whether the IndexRangeNode ranges array is valid");
if (haveRanges) { if (haveRanges) {
assertTrue(rn[0].ranges.length > 0, "Have IndexRangeNode with ranges"); assertTrue(rn[0].ranges[0].length > 0, "Have IndexRangeNode with ranges");
} }
else { else {
assertEqual(rn[0].ranges.length, 0, "Have IndexRangeNode with NO ranges"); assertEqual(rn[0].ranges[0].length, 0, "Have IndexRangeNode with NO ranges");
} }
}; };
var getRangeAttributes = function (plan) { var getRangeAttributes = function (plan) {
@ -230,12 +197,15 @@ function optimizerRuleTestSuite() {
var queries = [ var queries = [
"FOR v IN " + colName + " SORT v.c RETURN [v.a, v.b]", "FOR v IN " + colName + " SORT v.c RETURN [v.a, v.b]",
// todo: we use an index anyways right now. "FOR v IN " + colName + " SORT v.a DESC RETURN [v.a, v.b]",// currently only ASC supported. // todo: we use an index anyways right now.
// currently only ASC supported.
// "FOR v IN " + colName + " SORT v.a DESC RETURN [v.a, v.b]",
"FOR v IN " + colName + " SORT v.b, v.a RETURN [v.a, v.b]", "FOR v IN " + colName + " SORT v.b, v.a RETURN [v.a, v.b]",
"FOR v IN " + colName + " SORT v.c RETURN [v.a, v.b]", "FOR v IN " + colName + " SORT v.c RETURN [v.a, v.b]",
"FOR v IN " + colName + " SORT v.a + 1 RETURN [v.a, v.b]", "FOR v IN " + colName + " SORT v.a + 1 RETURN [v.a, v.b]",
"FOR v IN " + colName + " SORT CONCAT(TO_STRING(v.a), \"lol\") RETURN [v.a, v.b]", "FOR v IN " + colName + " SORT CONCAT(TO_STRING(v.a), \"lol\") RETURN [v.a, v.b]",
"FOR v IN " + colName + " FILTER v.a > 2 LIMIT 3 SORT v.a RETURN [v.a, v.b] ", // TODO: limit blocks sort atm. // TODO: limit blocks sort atm.
"FOR v IN " + colName + " FILTER v.a > 2 LIMIT 3 SORT v.a RETURN [v.a, v.b] ",
"FOR v IN " + colName + " FOR w IN " + colNameOther + " SORT v.a RETURN [v.a, v.b]" "FOR v IN " + colName + " FOR w IN " + colNameOther + " SORT v.a RETURN [v.a, v.b]"
]; ];
@ -254,8 +224,9 @@ function optimizerRuleTestSuite() {
testRuleHasEffect : function () { testRuleHasEffect : function () {
var allresults; var allresults;
var queries = [ var queries = [
// currently only ASC supported, but we use the index range anyways.
"FOR v IN " + colName + " SORT v.d DESC RETURN [v.d]",// currently only ASC supported, but we use the index range anyways. todo: this may change. // todo: this may change.
"FOR v IN " + colName + " SORT v.d DESC RETURN [v.d]",
"FOR v IN " + colName + " SORT v.d FILTER v.a > 2 LIMIT 3 RETURN [v.d] ", "FOR v IN " + colName + " SORT v.d FILTER v.a > 2 LIMIT 3 RETURN [v.d] ",
"FOR v IN " + colName + " FOR w IN 1..10 SORT v.d RETURN [v.d]", "FOR v IN " + colName + " FOR w IN 1..10 SORT v.d RETURN [v.d]",
@ -273,12 +244,10 @@ function optimizerRuleTestSuite() {
assertTrue(isEqual(QResults[0], QResults[1]), "Result " + i + " is Equal?"); assertTrue(isEqual(QResults[0], QResults[1]), "Result " + i + " is Equal?");
allresults = getQueryMultiplePlansAndExecutions(query, {}); allresults = getQueryMultiplePlansAndExecutions(query, {});
PY(allresults);
i++; i++;
}); });
}, },
/*
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test that rule has an effect, but the sort is kept in place since /// @brief test that rule has an effect, but the sort is kept in place since
@ -288,7 +257,8 @@ function optimizerRuleTestSuite() {
var queries = [ var queries = [
"FOR v IN " + colName + " FILTER v.a == 1 SORT v.a, v.c RETURN [v.a, v.b, v.c]", "FOR v IN " + colName + " FILTER v.a == 1 SORT v.a, v.c RETURN [v.a, v.b, v.c]",
"FOR v IN " + colName + " LET x = (FOR w IN " + colNameOther + " SORT w.j, w.h RETURN w.f ) SORT v.a RETURN [v.a]" "FOR v IN " + colName + " LET x = (FOR w IN "
+ colNameOther + " SORT w.j, w.h RETURN w.f ) SORT v.a RETURN [v.a]"
]; ];
var QResults = []; var QResults = [];
var i = 0; var i = 0;
@ -369,7 +339,8 @@ function optimizerRuleTestSuite() {
var QResults=[]; var QResults=[];
var i; var i;
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
@ -430,7 +401,8 @@ function optimizerRuleTestSuite() {
var QResults=[]; var QResults=[];
var i; var i;
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// -> use-index-for-sort alone. // -> use-index-for-sort alone.
@ -498,7 +470,8 @@ function optimizerRuleTestSuite() {
var QResults=[]; var QResults=[];
var i; var i;
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json; QResults[0] = AQL_EXECUTE(query, { }, paramNone).json;
@ -574,7 +547,8 @@ function optimizerRuleTestSuite() {
var QResults=[]; var QResults=[];
var i; var i;
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json; QResults[0] = AQL_EXECUTE(query, { }, paramNone).json;
// -> use-index-range alone. // -> use-index-range alone.
@ -586,8 +560,7 @@ function optimizerRuleTestSuite() {
// The IndexRangeNode created by this rule should be more clever, it knows the ranges. // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
var RAs = getRangeAttributes(XPresult); var RAs = getRangeAttributes(XPresult);
var first = getRangeAttribute(RAs, "v", "a", 1); var first = getRangeAttribute(RAs[0], "v", "a", 1);
assertEqual(first.lows.length, 0, "no non-constant low bounds"); assertEqual(first.lows.length, 0, "no non-constant low bounds");
assertEqual(first.highs.length, 0, "no non-constant high bounds"); assertEqual(first.highs.length, 0, "no non-constant high bounds");
assertEqual(first.lowConst.bound, 1, "correctness of bound"); assertEqual(first.lowConst.bound, 1, "correctness of bound");
@ -609,7 +582,8 @@ function optimizerRuleTestSuite() {
var XPresult; var XPresult;
var QResults=[]; var QResults=[];
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// -> use-index-range alone. // -> use-index-range alone.
@ -622,7 +596,7 @@ function optimizerRuleTestSuite() {
// The IndexRangeNode created by this rule should be more clever, it knows the ranges. // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
var RAs = getRangeAttributes(XPresult); var RAs = getRangeAttributes(XPresult);
var first = getRangeAttribute(RAs, "v", "a", 1); var first = getRangeAttribute(RAs[0], "v", "a", 1);
assertEqual(first.lowConst.bound, undefined, "no constant lower bound"); assertEqual(first.lowConst.bound, undefined, "no constant lower bound");
assertEqual(first.lows.length, 0, "no variable low bound"); assertEqual(first.lows.length, 0, "no variable low bound");
assertEqual(first.highs.length, 0, "no variable high bound"); assertEqual(first.highs.length, 0, "no variable high bound");
@ -639,7 +613,8 @@ function optimizerRuleTestSuite() {
var XPresult; var XPresult;
var QResults=[]; var QResults=[];
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// -> use-index-range alone. // -> use-index-range alone.
@ -652,7 +627,7 @@ function optimizerRuleTestSuite() {
// The IndexRangeNode created by this rule should be more clever, it knows the ranges. // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
var RAs = getRangeAttributes(XPresult); var RAs = getRangeAttributes(XPresult);
var first = getRangeAttribute(RAs, "v", "a", 1); var first = getRangeAttribute(RAs[0], "v", "a", 1);
assertEqual(first.highConst.bound, undefined, "no constant upper bound"); assertEqual(first.highConst.bound, undefined, "no constant upper bound");
assertEqual(first.highs.length, 0, "no variable high bound"); assertEqual(first.highs.length, 0, "no variable high bound");
@ -672,7 +647,8 @@ function optimizerRuleTestSuite() {
var XPresult; var XPresult;
var QResults=[]; var QResults=[];
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to
// re-sort the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// -> use-index-range alone. // -> use-index-range alone.
@ -685,7 +661,7 @@ function optimizerRuleTestSuite() {
// The IndexRangeNode created by this rule should be more clever, it knows the ranges. // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
var RAs = getRangeAttributes(XPresult); var RAs = getRangeAttributes(XPresult);
var first = getRangeAttribute(RAs, "v", "a", 1); var first = getRangeAttribute(RAs[0], "v", "a", 1);
assertEqual(first.highs.length, 0, "no variable high bounds"); assertEqual(first.highs.length, 0, "no variable high bounds");
assertEqual(first.lows.length, 0, "no variable low bounds"); assertEqual(first.lows.length, 0, "no variable low bounds");
@ -708,7 +684,8 @@ function optimizerRuleTestSuite() {
var XPresult; var XPresult;
var QResults=[]; var QResults=[];
// the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // the index we will compare to sorts by a & b, so we need to re-sort
// the result here to accomplish similarity.
QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// -> use-index-range alone. // -> use-index-range alone.
@ -739,7 +716,8 @@ function optimizerRuleTestSuite() {
// var XPresult; // var XPresult;
// var QResults=[]; // var QResults=[];
// //
// // the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // // the index we will compare to sorts by a & b, so we need to
// // re-sort the result here to accomplish similarity.
// QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); // QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// //
// // -> use-index-range alone. // // -> use-index-range alone.
@ -753,7 +731,7 @@ function optimizerRuleTestSuite() {
// // The IndexRangeNode created by this rule should be more clever, it knows the ranges. // // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
// var RAs = getRangeAttributes(XPresult); // var RAs = getRangeAttributes(XPresult);
// require("internal").print(RAs); // require("internal").print(RAs);
// var first = getRangeAttribute(RAs, "v", "a", 1); // var first = getRangeAttribute(RAs[0], "v", "a", 1);
// //
// require("internal").print(first); // require("internal").print(first);
// assertEqual(first.low.bound.vType, "int", "Type is int"); // assertEqual(first.low.bound.vType, "int", "Type is int");
@ -770,12 +748,14 @@ function optimizerRuleTestSuite() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testMultiRangeBandpass: function () { testMultiRangeBandpass: function () {
// TODO: OR isn't implemented // TODO: OR isn't implemented
// var query = "FOR v IN " + colName + " FILTER ((v.a > 3 && v.a < 5) || (v.a > 4 && v.a < 7)) RETURN [v.a, v.b]"; // var query = "FOR v IN " + colName +
// " FILTER ((v.a > 3 && v.a < 5) || (v.a > 4 && v.a < 7)) RETURN [v.a, v.b]";
// //
// var XPresult; // var XPresult;
// var QResults=[]; // var QResults=[];
// //
// // the index we will compare to sorts by a & b, so we need to re-sort the result here to accomplish similarity. // // the index we will compare to sorts by a & b, so we need to
// // re-sort the result here to accomplish similarity.
// QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray); // QResults[0] = AQL_EXECUTE(query, { }, paramNone).json.sort(sortArray);
// //
// // -> use-index-range alone. // // -> use-index-range alone.
@ -789,7 +769,7 @@ function optimizerRuleTestSuite() {
// // The IndexRangeNode created by this rule should be more clever, it knows the ranges. // // The IndexRangeNode created by this rule should be more clever, it knows the ranges.
// var RAs = getRangeAttributes(XPresult); // var RAs = getRangeAttributes(XPresult);
//// require("internal").print(RAs); //// require("internal").print(RAs);
// var first = getRangeAttribute(RAs, "v", "a", 1); // var first = getRangeAttribute(RAs[0], "v", "a", 1);
// //
//// require("internal").print(first); //// require("internal").print(first);
// assertEqual(first.low.bound.vType, "int", "Type is int"); // assertEqual(first.low.bound.vType, "int", "Type is int");
@ -800,7 +780,6 @@ function optimizerRuleTestSuite() {
// assertTrue(isEqual(QResults[0], QResults[1]), "Results are Equal?"); // assertTrue(isEqual(QResults[0], QResults[1]), "Results are Equal?");
} }
*/
}; };
} }