1
0
Fork 0

[3.3] Fix condition finders moving filters past modifications into index nodes (#6328)

This commit is contained in:
Dan Larkin-York 2018-09-04 11:05:53 -04:00 committed by Jan
parent 6476106048
commit 2bd9887407
4 changed files with 319 additions and 162 deletions

View File

@ -40,29 +40,32 @@ bool ConditionFinder::before(ExecutionNode* en) {
case EN::REMOTE:
case EN::SUBQUERY:
case EN::INDEX:
case EN::RETURN:
case EN::TRAVERSAL:
case EN::SHORTEST_PATH: {
// in these cases we simply ignore the intermediate nodes, note
// that we have taken care of nodes that could throw exceptions
// above.
break;
}
case EN::INSERT:
case EN::REMOVE:
case EN::REPLACE:
case EN::UPDATE:
case EN::UPSERT:
case EN::RETURN:
case EN::TRAVERSAL:
case EN::SHORTEST_PATH:
// in these cases we simply ignore the intermediate nodes, note
// that we have taken care of nodes that could throw exceptions
// above.
break;
case EN::LIMIT:
case EN::LIMIT: {
// LIMIT invalidates the sort expression we already found
_sorts.clear();
_filters.clear();
break;
}
case EN::SINGLETON:
case EN::NORESULTS:
case EN::NORESULTS: {
// in all these cases we better abort
return true;
}
case EN::FILTER: {
std::vector<Variable const*> invars(en->getVariablesUsedHere());

View File

@ -127,14 +127,14 @@ static bool IsSupportedNode(Variable const* pathVar, AstNode const* node) {
case NODE_TYPE_OPERATOR_BINARY_IN:
case NODE_TYPE_OPERATOR_BINARY_NIN: {
// the following types of expressions are not supported
// p.edges[0]._from op whatever attribute access
// p.edges[0]._from op whatever attribute access
// whatever attribute access op p.edges[0]._from
AstNode const* lhs = node->getMember(0);
AstNode const* rhs = node->getMember(1);
if (lhs->isAttributeAccessForVariable(pathVar, true)) {
// p.xxx op whatever
if (rhs->type != NODE_TYPE_VALUE &&
if (rhs->type != NODE_TYPE_VALUE &&
rhs->type != NODE_TYPE_ARRAY &&
rhs->type != NODE_TYPE_OBJECT &&
rhs->type != NODE_TYPE_REFERENCE) {
@ -142,7 +142,7 @@ static bool IsSupportedNode(Variable const* pathVar, AstNode const* node) {
}
} else if (rhs->isAttributeAccessForVariable(pathVar, true)) {
// whatever op p.xxx
if (lhs->type != NODE_TYPE_VALUE &&
if (lhs->type != NODE_TYPE_VALUE &&
lhs->type != NODE_TYPE_ARRAY &&
lhs->type != NODE_TYPE_OBJECT &&
lhs->type != NODE_TYPE_REFERENCE) {
@ -315,7 +315,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
patternStep++;
break;
}
case 3:
case 3:
if (depth != UINT64_MAX) {
// We are in depth pattern.
// The first Node we encount HAS to be indexed Access
@ -327,7 +327,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
// Search for the parent having this node.
patternStep = 6;
parentOfReplace = node;
// we need to know the depth at which a filter condition will
// access a path. Otherwise there are too many results
TRI_ASSERT(node->numMembers() == 2);
@ -380,7 +380,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
}
parentOfReplace = node;
replaceIdx = idx;
// Ok finally done.
// Ok finally done.
patternStep++;
break;
}
@ -505,25 +505,33 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
case EN::REMOTE:
case EN::SUBQUERY:
case EN::INDEX:
case EN::INSERT:
case EN::REMOVE:
case EN::REPLACE:
case EN::UPDATE:
case EN::UPSERT:
case EN::LIMIT:
case EN::RETURN:
case EN::SORT:
case EN::ENUMERATE_COLLECTION:
case EN::LIMIT:
case EN::SHORTEST_PATH:
case EN::SHORTEST_PATH: {
// in these cases we simply ignore the intermediate nodes, note
// that we have taken care of nodes that could throw exceptions
// above.
break;
}
case EN::INSERT:
case EN::REMOVE:
case EN::REPLACE:
case EN::UPDATE:
case EN::UPSERT: {
// modification invalidates the filter expression we already found
_condition = std::make_unique<Condition>(_plan->getAst());
_filterVariables.clear();
break;
}
case EN::SINGLETON:
case EN::NORESULTS:
case EN::NORESULTS: {
// in all these cases we better abort
return true;
}
case EN::FILTER: {
std::vector<Variable const*>&& invars = en->getVariablesUsedHere();
@ -587,7 +595,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
std::unordered_set<Variable const*> varsUsedByCondition;
auto originalFilterConditions = std::make_unique<Condition>(_plan->getAst());
for (size_t i = andNode->numMembers(); i > 0; --i) {
// Whenever we do not support a of the condition we have to throw it out
@ -602,7 +610,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
// For now we only! optimize filter conditions on the path
// So we skip all FILTERS not referencing the path
andNode->removeMemberUnchecked(i - 1);
continue;
continue;
}
// now we validate that there is no illegal variable used.
@ -628,7 +636,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
AstNode* cloned = andNode->getMember(i - 1)->clone(_plan->getAst());
int64_t indexedAccessDepth = -1;
size_t swappedIndex = 0;
// If we get here we can optimize this condition
if (!checkPathVariableAccessFeasible(_plan->getAst(), andNode, i - 1,
@ -646,7 +654,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
} else {
TRI_ASSERT(!conditionIsImpossible);
// remember the original filter conditions if we can remove them later
if (indexedAccessDepth == -1) {
originalFilterConditions->andCombine(cloned);
@ -655,7 +663,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
// is in [0..maxDepth], if the depth is not a concrete value
// then indexedAccessDepth would be INT64_MAX
originalFilterConditions->andCombine(cloned);
if ((int64_t)options->minDepth < indexedAccessDepth && !isTrueOnNull(cloned, pathVar)) {
// do not return paths shorter than the deepest path access
// Unless the condition evaluates to true on `null`.

View File

@ -87,9 +87,9 @@ function simpleInboundOutboundSuite () {
c = db._create(gn + 'v2', { numberOfShards: 7 });
c.insert({ _key: "test" });
c = db._createEdgeCollection(gn + 'e', { numberOfShards: 5 });
c.insert({ _from: gn + "v2/test", _to: gn + "v1/test" });
c.insert({ _from: gn + "v2/test", _to: gn + "v1/test" });
},
tearDown: function () {
@ -2490,7 +2490,62 @@ function complexFilteringSuite () {
// 1 Filter On D
assertEqual(stats.filtered, 1);
}
}
},
testModify: function () {
var query = `WITH ${vn}
FOR v, e, p IN 1..2 OUTBOUND @start @@ecol
UPDATE v WITH {updated: true} IN @@vcol
FILTER p.vertices[1].left == true
SORT v._key
RETURN v._key`;
var bindVars = {
'@ecol': en,
'@vcol': vn,
start: vertex.A
};
var cursor = db._query(query, bindVars);
assertEqual(cursor.count(), 3);
assertEqual(cursor.toArray(), ['B', 'C', 'F']);
var stats = cursor.getExtra().stats;
assertEqual(stats.writesExecuted, 6);
assertEqual(stats.scannedFull, 0);
if (isCluster) {
// 1 Primary lookup A
// 2 Edge Lookups (A)
// 2 Primary lookup B,D
// 2 Edge Lookups (2 B) (0 D)
// 2 Primary Lookups (C, F)
if (mmfilesEngine) {
assertTrue(stats.scannedIndex <= 13);
} else {
assertTrue(stats.scannedIndex <= 7);
}
} else {
// 2 Edge Lookups (A)
// 2 Primary (B, D) for Filtering
// 2 Edge Lookups (B)
// All edges are cached
// 1 Primary Lookups A -> B (B cached)
// 1 Primary Lookups A -> B -> C (A, B cached)
// 1 Primary Lookups A -> B -> F (A, B cached)
// With traverser-read-cache
// assertEqual(stats.scannedIndex, 9);
// Without traverser-read-cache
assertTrue(stats.scannedIndex <= 28);
/*
if(mmfilesEngine){
assertEqual(stats.scannedIndex, 17);
} else {
assertEqual(stats.scannedIndex, 13);
}
*/
}
// 1 Filter On D
assertEqual(stats.filtered, 3);
},
};
}

View File

@ -60,18 +60,18 @@ function optimizerIndexesTestSuite () {
testSameResultsConstAccess : function () {
var bind = { doc : { key: "test1" } };
var q1 = `RETURN (FOR item IN UnitTestsCollection FILTER (@doc.key == item._key) LIMIT 1 RETURN item)[0]`;
var q2 = `LET doc = @doc RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
var q1 = `RETURN (FOR item IN UnitTestsCollection FILTER (@doc.key == item._key) LIMIT 1 RETURN item)[0]`;
var q2 = `LET doc = @doc RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
var q3 = `LET doc = { key: "test1" } RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
var results = AQL_EXECUTE(q1, bind);
assertEqual(1, results.json.length);
assertEqual("test1", results.json[0]._key);
results = AQL_EXECUTE(q2, bind);
assertEqual(1, results.json.length);
assertEqual("test1", results.json[0]._key);
results = AQL_EXECUTE(q3);
assertEqual(1, results.json.length);
assertEqual("test1", results.json[0]._key);
@ -91,7 +91,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 22 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -112,7 +112,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -134,7 +134,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
assertEqual(0, results.stats.scannedFull);
@ -159,13 +159,13 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
assertEqual(0, results.stats.scannedFull);
assertEqual(4, results.stats.scannedIndex);
},
testUsePrimaryIdNoDocuments : function () {
var values = [ "UnitTestsCollection/test1", "UnitTestsCollection/test2", "UnitTestsCollection/test21", "UnitTestsCollection/test30" ];
var query = "FOR i IN " + c.name() + " FILTER i._id IN " + JSON.stringify(values) + " RETURN 1";
@ -180,7 +180,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1, 1, 1, 1 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -202,7 +202,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -226,7 +226,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 6 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -246,7 +246,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -267,7 +267,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -289,7 +289,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
assertEqual(0, results.stats.scannedFull);
@ -311,7 +311,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
assertEqual(0, results.stats.scannedFull);
@ -333,7 +333,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -354,7 +354,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -375,7 +375,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -396,7 +396,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -417,7 +417,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -438,7 +438,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -459,7 +459,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -480,7 +480,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -501,7 +501,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -543,7 +543,7 @@ function optimizerIndexesTestSuite () {
assertEqual("SingletonNode", nodeTypes[0], query);
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual([ 12 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -577,7 +577,7 @@ function optimizerIndexesTestSuite () {
// retry without index
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
c.dropIndex(idx);
results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertTrue(results.stats.scannedFull > 0);
@ -611,7 +611,7 @@ function optimizerIndexesTestSuite () {
// retry without index
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
c.dropIndex(idx);
results = AQL_EXECUTE(query);
assertEqual([ 'one', 'one' ], results.json, query);
assertTrue(results.stats.scannedFull > 0);
@ -642,11 +642,11 @@ function optimizerIndexesTestSuite () {
assertEqual([ 'one', 'one' ], results.json, query);
assertEqual(0, results.stats.scannedFull);
assertTrue(results.stats.scannedIndex > 0);
// retry without index
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
c.dropIndex(idx);
results = AQL_EXECUTE(query);
assertEqual([ 'one', 'one' ], results.json, query);
assertTrue(results.stats.scannedFull > 0);
@ -677,11 +677,11 @@ function optimizerIndexesTestSuite () {
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
assertEqual(0, results.stats.scannedIndex);
// retry without index
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
c.dropIndex(idx);
results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
@ -711,11 +711,11 @@ function optimizerIndexesTestSuite () {
assertEqual([ ], results.json, query);
assertEqual(0, results.stats.scannedFull);
assertTrue(results.stats.scannedIndex > 0);
// retry without index
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
c.dropIndex(idx);
results = AQL_EXECUTE(query);
assertEqual([ ], results.json, query);
assertTrue(results.stats.scannedFull > 0);
@ -829,7 +829,7 @@ function optimizerIndexesTestSuite () {
assertEqual(0, results.stats.scannedFull);
assertTrue(results.stats.scannedIndex > 0);
},
testUseIndexSimpleNoDocuments : function () {
var query = "FOR i IN " + c.name() + " FILTER i.value >= 10 SORT i.value LIMIT 10 RETURN 1";
@ -982,15 +982,15 @@ function optimizerIndexesTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testMultipleSubqueries : function () {
var query = "LET a = (FOR x IN " + c.name() + " FILTER x._key == 'test1' RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x._key == 'test2' RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x._key == 'test3' RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x._key == 'test4' RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x._key == 'test5' RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x._key == 'test6' RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x._key == 'test7' RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x._key == 'test8' RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x._key == 'test9' RETURN x._key) " +
var query = "LET a = (FOR x IN " + c.name() + " FILTER x._key == 'test1' RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x._key == 'test2' RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x._key == 'test3' RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x._key == 'test4' RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x._key == 'test5' RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x._key == 'test6' RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x._key == 'test7' RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x._key == 'test8' RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x._key == 'test9' RETURN x._key) " +
"LET j = (FOR x IN " + c.name() + " FILTER x._key == 'test10' RETURN x._key) " +
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
@ -1023,7 +1023,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
},
@ -1033,15 +1033,15 @@ function optimizerIndexesTestSuite () {
testMultipleSubqueriesMultipleIndexes : function () {
c.ensureHashIndex("value"); // now we have a hash and a skiplist index
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 RETURN x._key) " +
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
@ -1079,7 +1079,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
},
@ -1090,15 +1090,15 @@ function optimizerIndexesTestSuite () {
testMultipleSubqueriesHashIndexes : function () {
c.dropIndex(c.getIndexes()[1]); // drop skiplist index
c.ensureHashIndex("value");
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 RETURN x._key) " +
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
@ -1131,7 +1131,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
},
@ -1178,7 +1178,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ 'test0', 'test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8', 'test9' ], results.json);
},
@ -1217,7 +1217,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ 'test0', 'test0', 'test1', 'test0', 'test1', 'test2', 'test0', 'test1', 'test2', 'test3' ], results.json);
},
@ -1268,7 +1268,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ 'test0', 'test1', 'test2', 'test3' ], results.json);
},
@ -1278,21 +1278,21 @@ function optimizerIndexesTestSuite () {
testSubqueryMadness : function () {
c.ensureHashIndex("value"); // now we have a hash and a skiplist index
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
var explain = AQL_EXPLAIN(query);
var plan = explain.plan;
var walker = function (nodes, func) {
nodes.forEach(function(node) {
if (node.type === "SubqueryNode") {
@ -1303,7 +1303,7 @@ function optimizerIndexesTestSuite () {
};
var indexNodes = 0, collectionNodes = 0;
walker(plan.nodes, function (node) {
if (node.type === "IndexNode") {
++indexNodes;
@ -1324,7 +1324,7 @@ function optimizerIndexesTestSuite () {
var results = AQL_EXECUTE(query);
assertEqual(0, results.stats.scannedFull);
assertNotEqual(0, results.stats.scannedIndex);
assertNotEqual(0, results.stats.scannedIndex);
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
},
@ -1360,15 +1360,15 @@ function optimizerIndexesTestSuite () {
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a ] RETURN i.value", [ 35 ] ],
[ "FOR i IN " + c.name() + " FILTER i._key IN [ PASSTHRU('test35') ] RETURN i.value", [ 35 ] ],
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, a, a ] RETURN i.value", [ 35 ] ],
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ 'test35', 'test36' ] RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test-9') FOR i IN " + c.name() + " FILTER i._key IN [ b, b, a, b, c ] RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a ] || i._key IN [ b, c ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c, d ] || i._key IN [ a, b, c, d ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ 'test35', 'test36' ] RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test-9') FOR i IN " + c.name() + " FILTER i._key IN [ b, b, a, b, c ] RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a ] || i._key IN [ b, c ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c, d ] || i._key IN [ a, b, c, d ] RETURN i.value", [ 35, 36, 37 ] ],
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a RETURN i.value", [ 35 ] ],
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == a RETURN i.value", [ 35 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b || i._key == c || i._key == d RETURN i.value", [ 35, 36, 37 ] ]
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b RETURN i.value", [ 35, 36 ] ],
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b || i._key == c || i._key == d RETURN i.value", [ 35, 36, 37 ] ]
];
queries.forEach(function(query) {
@ -1384,7 +1384,7 @@ function optimizerIndexesTestSuite () {
results.json.forEach(function(value) {
assertNotEqual(-1, query[1].indexOf(value), query);
});
assertTrue(results.stats.scannedIndex < 10);
assertEqual(0, results.stats.scannedFull);
});
@ -1419,7 +1419,7 @@ function optimizerIndexesTestSuite () {
assertEqual(2, results.stats.scannedIndex);
assertEqual(0, results.stats.scannedFull);
},
testIndexOrHashNoDocuments : function () {
c.ensureHashIndex("value");
var query = "FOR i IN " + c.name() + " FILTER i.value == 1 || i.value == 9 RETURN 1";
@ -1580,7 +1580,7 @@ function optimizerIndexesTestSuite () {
assertEqual(2, results.stats.scannedIndex);
assertEqual(0, results.stats.scannedFull);
},
testIndexOrSkiplistNoDocuments : function () {
var query = "FOR i IN " + c.name() + " FILTER i.value == 1 || i.value == 9 RETURN 1";
@ -1944,11 +1944,11 @@ function optimizerIndexesTestSuite () {
assertEqual(0, results.stats.scannedFull);
assertTrue(results.stats.scannedIndex > 0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test index usage
////////////////////////////////////////////////////////////////////////////////
testIndexOrNoIndexBecauseOfDifferentAttributes : function () {
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: 1 } IN " + c.name());
@ -1973,7 +1973,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2, results.json.length);
assertEqual(2, results.json.length);
assertTrue(results.stats.scannedFull > 0);
assertEqual(0, results.stats.scannedIndex);
});
@ -2011,7 +2011,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length, query);
assertEqual(1, results.json.length, query);
assertTrue(results.stats.scannedFull > 0);
assertEqual(0, results.stats.scannedIndex);
});
@ -2067,7 +2067,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2117,7 +2117,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2143,7 +2143,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2196,16 +2196,16 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test index usage
////////////////////////////////////////////////////////////////////////////////
testIndexAndDespiteOr : function () {
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: 1 } IN " + c.name());
@ -2225,7 +2225,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2, results.json.length, query);
assertEqual(2, results.json.length, query);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2273,7 +2273,7 @@ function optimizerIndexesTestSuite () {
// The condition is impossible. We do not care for indexes.
// assertNotEqual(-1, nodeTypes.indexOf("NoResultsNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(0, results.json.length);
assertEqual(0, results.json.length);
assertTrue(results.stats.scannedIndex >= 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2312,7 +2312,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2000, results.json.length);
assertEqual(2000, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertTrue(results.stats.scannedFull > 0);
});
@ -2348,7 +2348,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2000, results.json.length);
assertEqual(2000, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertTrue(results.stats.scannedFull > 0);
});
@ -2372,7 +2372,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2000, results.json.length);
assertEqual(2000, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertTrue(results.stats.scannedFull > 0);
});
@ -2404,7 +2404,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2000, results.json.length);
assertEqual(2000, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertTrue(results.stats.scannedFull > 0);
});
@ -2437,7 +2437,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertEqual(2, results.json[0].value);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
@ -2474,7 +2474,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertEqual(2, results.json[0].value);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
@ -2511,7 +2511,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertEqual(2, results.json[0].value);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
@ -2551,7 +2551,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertEqual(2, results.json[0].value);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
@ -2588,7 +2588,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(1, results.json.length);
assertEqual(1, results.json.length);
assertEqual(2, results.json[0].value);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
@ -2617,7 +2617,7 @@ function optimizerIndexesTestSuite () {
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query[0]);
assertEqual(query[1], results.json.length);
assertEqual(query[1], results.json.length);
assertTrue(results.stats.scannedFull > 0);
assertEqual(0, results.stats.scannedIndex);
});
@ -2651,7 +2651,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query[0]);
assertEqual(query[1], results.json.length);
assertEqual(query[1], results.json.length);
assertTrue(results.stats.scannedIndex > 0);
assertEqual(0, results.stats.scannedFull);
});
@ -2664,7 +2664,7 @@ function optimizerIndexesTestSuite () {
testIndexUsageIn : function () {
c.ensureHashIndex("value2");
c.ensureSkiplist("value3");
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: i.value } IN " + c.name());
var queries = [
@ -2707,12 +2707,12 @@ function optimizerIndexesTestSuite () {
[ "LET a = PASSTHRU({ ids: ['test23', 'test42'] }) FOR i IN " + c.name() + " FILTER i._key IN a.ids RETURN i._key", [ 'test23', 'test42' ] ],
[ "LET a = PASSTHRU({ ids: [23, 42] }) FOR i IN " + c.name() + " FILTER i.value2 IN a.ids RETURN i.value2", [ 23, 42 ] ],
[ "LET a = PASSTHRU({ ids: [23, 42] }) FOR i IN " + c.name() + " FILTER i.value3 IN a.ids RETURN i.value2", [ 23, 42 ] ],
// non-arrays. should not fail but return no results
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i._key IN a RETURN i._key", [ ] ],
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i.value2 IN a RETURN i.value2", [ ] ],
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i.value3 IN a RETURN i.value2", [ ] ]
];
@ -2725,7 +2725,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
var results = AQL_EXECUTE(query[0]);
assertEqual(query[1].length, results.json.length, query);
assertEqual(query[1].length, results.json.length, query);
assertEqual(query[1].sort(), results.json.sort(), query);
assertTrue(results.stats.scannedIndex >= 0);
assertEqual(0, results.stats.scannedFull);
@ -2739,7 +2739,7 @@ function optimizerIndexesTestSuite () {
testIndexUsageInNoIndex : function () {
c.ensureHashIndex("value2");
c.ensureSkiplist("value3");
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: i.value } IN " + c.name());
var queries = [
@ -2758,7 +2758,7 @@ function optimizerIndexesTestSuite () {
assertNotEqual(-1, nodeTypes.indexOf("NoResultsNode"), query);
var results = AQL_EXECUTE(query[0]);
assertEqual(0, results.json.length);
assertEqual(0, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertEqual(0, results.stats.scannedFull);
});
@ -3525,7 +3525,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
db._drop("UnitTestsCollection2");
c1 = db._create("UnitTestsCollection1");
c2 = db._create("UnitTestsCollection2");
var i;
for (i = 0; i < 200; ++i) {
c1.save({ _key: "test" + i, value: i });
@ -3563,7 +3563,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
@ -3594,7 +3594,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
@ -3626,7 +3626,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
@ -3658,7 +3658,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
@ -3690,7 +3690,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
@ -3722,13 +3722,105 @@ function optimizerIndexesMultiCollectionTestSuite () {
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", subNodeTypes[0], query);
var idx = subNodeTypes.indexOf("IndexNode");
assertNotEqual(-1, idx, query); // index used for inner query
assertEqual("skiplist", plan.nodes[sub].subquery.nodes[idx].indexes[0].type);
assertEqual(-1, subNodeTypes.indexOf("SortNode"), query); // must not have sort node for inner query
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test index usage
////////////////////////////////////////////////////////////////////////////////
testPreventMoveFilterPastModify1 : function () {
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
var query = `
FOR i IN ${c1.name()}
FOR j IN ${c2.name()}
UPDATE j WITH { tick: i } in ${c2.name()}
FILTER i.value == 1
RETURN [i, NEW]
`;
var plan = AQL_EXPLAIN(query).plan;
var nodeTypes = plan.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", nodeTypes[0], query);
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
assertNotEqual(-1, nodeTypes.indexOf("FilterNode"), query); // post filter
},
testPreventMoveFilterPastModify2 : function () {
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
var query = `
FOR i IN ${c1.name()}
FOR j IN ${c2.name()}
UPDATE j WITH { tick: i } in ${c2.name()}
FILTER j.value == 1
RETURN [i, NEW]
`;
var plan = AQL_EXPLAIN(query).plan;
var nodeTypes = plan.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", nodeTypes[0], query);
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
assertNotEqual(-1, nodeTypes.indexOf("FilterNode"), query); // post filter
},
testPreventMoveSortPastModify1 : function () {
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
var query = `
FOR i IN ${c1.name()}
FOR j IN ${c2.name()}
UPDATE j WITH { tick: i } in ${c2.name()}
SORT i.value
RETURN [i, NEW]
`;
var plan = AQL_EXPLAIN(query).plan;
var nodeTypes = plan.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", nodeTypes[0], query);
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
assertNotEqual(-1, nodeTypes.indexOf("SortNode"), query); // post filter
},
testPreventMoveSortPastModify2 : function () {
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
var query = `
FOR i IN ${c1.name()}
FOR j IN ${c2.name()}
UPDATE j WITH { tick: i } in ${c2.name()}
SORT NEW.value
RETURN [i, NEW]
`;
var plan = AQL_EXPLAIN(query).plan;
var nodeTypes = plan.nodes.map(function(node) {
return node.type;
});
assertEqual("SingletonNode", nodeTypes[0], query);
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
assertNotEqual(-1, nodeTypes.indexOf("SortNode"), query); // post filter
},
};
}
@ -3741,4 +3833,3 @@ jsunity.run(optimizerIndexesTestSuite);
jsunity.run(optimizerIndexesMultiCollectionTestSuite);
return jsunity.done();