diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index 460f905159..d06aaa712d 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -478,27 +478,36 @@ void findShardKeysInExpression(arangodb::aql::AstNode const* root, return; } - if (root->type == arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_OR) { - if (root->numMembers() != 1) { - return; - } - root = root->getMember(0); - if (root == nullptr || - root->type != arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_AND) { - return; - } - - for (size_t i = 0; i < root->numMembers(); ++i) { - if (root->getMember(i) != nullptr && - root->getMember(i)->type == - arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_EQ) { - findShardKeyInComparison(root->getMember(i), inputVariable, toFind, - builder); + switch (root->type) { + case arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_OR: { + if (root->numMembers() != 1) { + return; } + root = root->getMember(0); + if (root == nullptr || + root->type != + arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_AND) { + return; + } + } // falls through + case arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_AND: + case arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_AND: { + for (size_t i = 0; i < root->numMembers(); ++i) { + if (root->getMember(i) != nullptr && + root->getMember(i)->type == + arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_EQ) { + findShardKeyInComparison(root->getMember(i), inputVariable, toFind, + builder); + } + } + break; } - } else if (root->type == - arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_EQ) { - findShardKeyInComparison(root, inputVariable, toFind, builder); + case arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_EQ: { + findShardKeyInComparison(root, inputVariable, toFind, builder); + break; + } + default: + break; } } diff --git a/tests/js/server/aql/aql-shardids-cluster.js b/tests/js/server/aql/aql-shardids-cluster.js index 1fb7ec6353..258c678d16 100644 --- a/tests/js/server/aql/aql-shardids-cluster.js +++ b/tests/js/server/aql/aql-shardids-cluster.js @@ -123,6 +123,7 @@ function ahuacatlShardIdsOptimizationTestSuite() { const shardKey = "value"; const shardKey1 = "value"; const shardKey2 = "value"; + const extraKey = "extra"; const numberOfShards = 9; const tearDown = () => { @@ -182,7 +183,7 @@ function ahuacatlShardIdsOptimizationTestSuite() { let docs = []; for (let i = 0; i < 100; ++i) { - docs.push({ "value" : i % 25, "joinValue" : i % 5 }); + docs.push({ "value" : i % 25, "joinValue" : i % 5, "extra": true }); } collection.save(docs); @@ -428,6 +429,90 @@ function ahuacatlShardIdsOptimizationTestSuite() { } }, + testMultipleKeysSameFilter: function () { + dropIndexes(collectionByKey); + collectionByKey.ensureHashIndex(shardKey); + + for (let i = 0; i < 24; ++i) { + const query = ` + FOR doc IN ${cnKey} + FILTER doc.${shardKey} == ${i} && doc.${extraKey} == true + RETURN doc + `; + validatePlan(query, "IndexNode", collectionByKey); + + let res = db._query(query, {}, disableSingleDocOp).toArray(); + assertEqual(4, res.length); + for (let doc of res) { + assertTrue(i === doc.value); + assertTrue(true === doc.extra); + } + } + }, + + testMultipleKeysSameFilterNoIndex: function () { + dropIndexes(collectionByKey); + + for (let i = 0; i < 24; ++i) { + const query = ` + FOR doc IN ${cnKey} + FILTER doc.${shardKey} == ${i} && doc.${extraKey} == true + RETURN doc + `; + validatePlan(query, "EnumerateCollectionNode", collectionByKey); + + let res = db._query(query, {}, disableSingleDocOp).toArray(); + assertEqual(4, res.length); + for (let doc of res) { + assertTrue(i === doc.value); + assertTrue(true === doc.extra); + } + } + }, + + testMultipleKeysDifferentFilter: function () { + dropIndexes(collectionByKey); + collectionByKey.ensureHashIndex(shardKey); + + for (let i = 0; i < 24; ++i) { + const query = ` + FOR doc IN ${cnKey} + FILTER doc.${shardKey} == ${i} + FILTER doc.${extraKey} == true + RETURN doc + `; + validatePlan(query, "IndexNode", collectionByKey); + + let res = db._query(query, {}, disableSingleDocOp).toArray(); + assertEqual(4, res.length); + for (let doc of res) { + assertTrue(i === doc.value); + assertTrue(true === doc.extra); + } + } + }, + + testMultipleKeysDifferentFilterNoIndex: function () { + dropIndexes(collectionByKey); + + for (let i = 0; i < 24; ++i) { + const query = ` + FOR doc IN ${cnKey} + FILTER doc.${shardKey} == ${i} + FILTER doc.${extraKey} == true + RETURN doc + `; + validatePlan(query, "EnumerateCollectionNode", collectionByKey); + + let res = db._query(query, {}, disableSingleDocOp).toArray(); + assertEqual(4, res.length); + for (let doc of res) { + assertTrue(i === doc.value); + assertTrue(true === doc.extra); + } + } + }, + testMultipleShardsOr : function () { dropIndexes(collectionByKey); collectionByKey.ensureHashIndex(shardKey);