diff --git a/arangod/Indexes/HashIndex.cpp b/arangod/Indexes/HashIndex.cpp index f6a318e932..1f1ada3732 100644 --- a/arangod/Indexes/HashIndex.cpp +++ b/arangod/Indexes/HashIndex.cpp @@ -812,7 +812,7 @@ IndexIterator* HashIndex::iteratorForCondition (IndexIteratorContext* context, triagens::aql::Ast* ast, triagens::aql::AstNode const* node, triagens::aql::Variable const* reference, - bool const reverse) const { + bool reverse) const { TRI_ASSERT(node->type == aql::NODE_TYPE_OPERATOR_NARY_AND); SimpleAttributeEqualityMatcher matcher(fields()); @@ -824,13 +824,17 @@ IndexIterator* HashIndex::iteratorForCondition (IndexIteratorContext* context, std::vector permutationStates; permutationStates.reserve(n); size_t maxPermutations = 1; + + std::pair> paramPair; for (size_t i = 0; i < n; ++i) { - std::pair> paramPair; auto comp = allVals->getMemberUnchecked(i); auto attrNode = comp->getMember(0); auto valNode = comp->getMember(1); + paramPair.first = nullptr; + paramPair.second.clear(); + if (! attrNode->isAttributeAccessForVariable(paramPair) || paramPair.first != reference) { attrNode = comp->getMember(1); valNode = comp->getMember(0); diff --git a/arangod/Indexes/HashIndex.h b/arangod/Indexes/HashIndex.h index cbbab0dc00..a3fba97814 100644 --- a/arangod/Indexes/HashIndex.h +++ b/arangod/Indexes/HashIndex.h @@ -192,7 +192,7 @@ namespace triagens { triagens::aql::Ast*, triagens::aql::AstNode const*, triagens::aql::Variable const*, - bool const) const override; + bool) const override; triagens::aql::AstNode* specializeCondition (triagens::aql::AstNode*, triagens::aql::Variable const*) const override; diff --git a/arangod/Indexes/Index.cpp b/arangod/Indexes/Index.cpp index 9dab1e75e9..7bae137913 100644 --- a/arangod/Indexes/Index.cpp +++ b/arangod/Indexes/Index.cpp @@ -553,7 +553,8 @@ triagens::aql::AstNode* Index::specializeCondition (triagens::aql::AstNode* node bool Index::canUseConditionPart (triagens::aql::AstNode const* access, triagens::aql::AstNode const* other, triagens::aql::AstNode const* op, - triagens::aql::Variable const* reference) const { + triagens::aql::Variable const* reference, + bool isExecution) const { if (_sparse) { if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_NIN) { @@ -614,6 +615,11 @@ bool Index::canUseConditionPart (triagens::aql::AstNode const* access, } } + if (isExecution) { + // in execution phase, we do not need to check the variable usage again + return true; + } + // test if the reference variable is contained on both side of the expression std::unordered_set variables; if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN && diff --git a/arangod/Indexes/Index.h b/arangod/Indexes/Index.h index 0ed33abb03..13ea06b363 100644 --- a/arangod/Indexes/Index.h +++ b/arangod/Indexes/Index.h @@ -370,7 +370,8 @@ namespace triagens { bool canUseConditionPart (triagens::aql::AstNode const* access, triagens::aql::AstNode const* other, triagens::aql::AstNode const* op, - triagens::aql::Variable const* reference) const; + triagens::aql::Variable const* reference, + bool) const; // ----------------------------------------------------------------------------- // --SECTION-- protected variables diff --git a/arangod/Indexes/SimpleAttributeEqualityMatcher.cpp b/arangod/Indexes/SimpleAttributeEqualityMatcher.cpp index c1e230ccab..c165785c92 100644 --- a/arangod/Indexes/SimpleAttributeEqualityMatcher.cpp +++ b/arangod/Indexes/SimpleAttributeEqualityMatcher.cpp @@ -72,8 +72,8 @@ bool SimpleAttributeEqualityMatcher::matchOne (triagens::arango::Index const* in if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { TRI_ASSERT(op->numMembers() == 2); // EQ is symmetric - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference) || - accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false) || + accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, false)) { // we can use the index calculateIndexCosts(index, itemsInIndex, estimatedItems, estimatedCost); return true; @@ -81,7 +81,7 @@ bool SimpleAttributeEqualityMatcher::matchOne (triagens::arango::Index const* in } else if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false)) { // we can use the index // use slightly different cost calculation for IN that for EQ calculateIndexCosts(index, itemsInIndex, estimatedItems, estimatedCost); @@ -118,8 +118,8 @@ bool SimpleAttributeEqualityMatcher::matchAll (triagens::arango::Index const* in if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference) || - accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false) || + accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, false)) { if (_found.size() == _attributes.size()) { // got enough attributes break; @@ -129,7 +129,7 @@ bool SimpleAttributeEqualityMatcher::matchAll (triagens::arango::Index const* in else if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false)) { auto m = op->getMember(1); if (m->type != triagens::aql::NODE_TYPE_EXPANSION && m->numMembers() > 1) { // attr IN [ a, b, c ] => this will produce multiple items, so count them! @@ -182,10 +182,10 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::getOne (triagens::aql::A op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); // note: accessFitsIndex will increase _found in case of a condition match - bool matches = accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference); + bool matches = accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, true); if (! matches && op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { - matches = accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference); + matches = accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, true); } if (matches) { @@ -223,11 +223,11 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::getAll (triagens::aql::A op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); // note: accessFitsIndex will increase _found in case of a condition match - bool matches = accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference); + bool matches = accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, true); if (! matches && op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { // EQ is symmetric - matches = accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference); + matches = accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, true); } if (matches) { @@ -238,14 +238,14 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::getAll (triagens::aql::A if (_found.size() == _attributes.size()) { // got enough matches - std::unique_ptr node(ast->createNodeNaryOperator(triagens::aql::NODE_TYPE_OPERATOR_NARY_AND)); + auto node = ast->createNodeNaryOperator(triagens::aql::NODE_TYPE_OPERATOR_NARY_AND); for (auto& it : parts) { - node->addMember(ast->clone(it)); + node->addMember(it); } // done - return node.release(); + return node; } } } @@ -274,8 +274,8 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::specializeOne (triagens: if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { TRI_ASSERT(op->numMembers() == 2); // EQ is symmetric - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference) || - accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false) || + accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, false)) { // we can use the index // now return only the child node we need while (node->numMembers() > 0) { @@ -289,7 +289,7 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::specializeOne (triagens: else if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false)) { // we can use the index // now return only the child node we need while (node->numMembers() > 0) { @@ -325,8 +325,8 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::specializeAll (triagens: if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference) || - accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false) || + accessFitsIndex(index, op->getMember(1), op->getMember(0), op, reference, false)) { children.emplace_back(op); TRI_IF_FAILURE("SimpleAttributeMatcher::specializeAllChildrenEQ") { THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); @@ -339,7 +339,7 @@ triagens::aql::AstNode* SimpleAttributeEqualityMatcher::specializeAll (triagens: } else if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) { TRI_ASSERT(op->numMembers() == 2); - if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference)) { + if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, reference, false)) { children.emplace_back(op); TRI_IF_FAILURE("SimpleAttributeMatcher::specializeAllChildrenIN") { THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG); @@ -433,8 +433,9 @@ bool SimpleAttributeEqualityMatcher::accessFitsIndex (triagens::arango::Index co triagens::aql::AstNode const* access, triagens::aql::AstNode const* other, triagens::aql::AstNode const* op, - triagens::aql::Variable const* reference) { - if (! index->canUseConditionPart(access, other, op, reference)) { + triagens::aql::Variable const* reference, + bool isExecution) { + if (! index->canUseConditionPart(access, other, op, reference, isExecution)) { return false; } diff --git a/arangod/Indexes/SimpleAttributeEqualityMatcher.h b/arangod/Indexes/SimpleAttributeEqualityMatcher.h index b3ae6a2997..fd481a7822 100644 --- a/arangod/Indexes/SimpleAttributeEqualityMatcher.h +++ b/arangod/Indexes/SimpleAttributeEqualityMatcher.h @@ -157,7 +157,8 @@ namespace triagens { triagens::aql::AstNode const*, triagens::aql::AstNode const*, triagens::aql::AstNode const*, - triagens::aql::Variable const*); + triagens::aql::Variable const*, + bool); // ----------------------------------------------------------------------------- // --SECTION-- private variables diff --git a/arangod/Indexes/SkiplistIndex.cpp b/arangod/Indexes/SkiplistIndex.cpp index a7f2c7abd3..8cb5312b12 100644 --- a/arangod/Indexes/SkiplistIndex.cpp +++ b/arangod/Indexes/SkiplistIndex.cpp @@ -1047,8 +1047,9 @@ bool SkiplistIndex::accessFitsIndex (triagens::aql::AstNode const* access, triagens::aql::AstNode const* other, triagens::aql::AstNode const* op, triagens::aql::Variable const* reference, - std::unordered_map>& found) const { - if (! this->canUseConditionPart(access, other, op, reference)) { + std::unordered_map>& found, + bool isExecution) const { + if (! this->canUseConditionPart(access, other, op, reference, isExecution)) { return false; } @@ -1100,7 +1101,8 @@ bool SkiplistIndex::accessFitsIndex (triagens::aql::AstNode const* access, void SkiplistIndex::matchAttributes (triagens::aql::AstNode const* node, triagens::aql::Variable const* reference, std::unordered_map>& found, - size_t& values) const { + size_t& values, + bool isExecution) const { for (size_t i = 0; i < node->numMembers(); ++i) { auto op = node->getMember(i); @@ -1111,12 +1113,12 @@ void SkiplistIndex::matchAttributes (triagens::aql::AstNode const* node, case triagens::aql::NODE_TYPE_OPERATOR_BINARY_GT: case triagens::aql::NODE_TYPE_OPERATOR_BINARY_GE: TRI_ASSERT(op->numMembers() == 2); - accessFitsIndex(op->getMember(0), op->getMember(1), op, reference, found); - accessFitsIndex(op->getMember(1), op->getMember(0), op, reference, found); + accessFitsIndex(op->getMember(0), op->getMember(1), op, reference, found, isExecution); + accessFitsIndex(op->getMember(1), op->getMember(0), op, reference, found, isExecution); break; case triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN: - if (accessFitsIndex(op->getMember(0), op->getMember(1), op, reference, found)) { + if (accessFitsIndex(op->getMember(0), op->getMember(1), op, reference, found, isExecution)) { auto m = op->getMember(1); if (m->type != triagens::aql::NODE_TYPE_EXPANSION && m->numMembers() > 1) { // attr IN [ a, b, c ] => this will produce multiple items, so count them! @@ -1124,7 +1126,7 @@ void SkiplistIndex::matchAttributes (triagens::aql::AstNode const* node, } } else { - accessFitsIndex(op->getMember(1), op->getMember(0), op, reference, found); + accessFitsIndex(op->getMember(1), op->getMember(0), op, reference, found, isExecution); } break; @@ -1141,7 +1143,7 @@ bool SkiplistIndex::supportsFilterCondition (triagens::aql::AstNode const* node, double& estimatedCost) const { std::unordered_map> found; size_t values = 0; - matchAttributes(node, reference, found, values); + matchAttributes(node, reference, found, values, false); bool lastContainsEquality = true; size_t attributesCovered = 0; @@ -1276,7 +1278,7 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex triagens::aql::Ast* ast, triagens::aql::AstNode const* node, triagens::aql::Variable const* reference, - bool const reverse) const { + bool reverse) const { // Create the skiplistOperator for the IndexLookup if (node == nullptr) { @@ -1295,7 +1297,7 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex } std::unordered_map> found; size_t unused = 0; - matchAttributes(node, reference, found, unused); + matchAttributes(node, reference, found, unused, true); // found contains all attributes that are relevant for this node. // It might be less than fields(). @@ -1537,7 +1539,7 @@ triagens::aql::AstNode* SkiplistIndex::specializeCondition (triagens::aql::AstNo triagens::aql::Variable const* reference) const { std::unordered_map> found; size_t values = 0; - matchAttributes(node, reference, found, values); + matchAttributes(node, reference, found, values, false); std::vector children; bool lastContainsEquality = true; diff --git a/arangod/Indexes/SkiplistIndex.h b/arangod/Indexes/SkiplistIndex.h index e6196679ad..2e30672f47 100644 --- a/arangod/Indexes/SkiplistIndex.h +++ b/arangod/Indexes/SkiplistIndex.h @@ -319,7 +319,7 @@ namespace triagens { triagens::aql::Ast*, triagens::aql::AstNode const*, triagens::aql::Variable const*, - bool const) const override; + bool) const override; triagens::aql::AstNode* specializeCondition (triagens::aql::AstNode*, triagens::aql::Variable const*) const override; @@ -344,12 +344,14 @@ namespace triagens { triagens::aql::AstNode const*, triagens::aql::AstNode const*, triagens::aql::Variable const*, - std::unordered_map>&) const; + std::unordered_map>&, + bool) const; void matchAttributes (triagens::aql::AstNode const*, triagens::aql::Variable const*, std::unordered_map>&, - size_t&) const; + size_t&, + bool) const; // ----------------------------------------------------------------------------- // --SECTION-- private variables