diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 3a2bf9f275..7bb3b32704 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -1179,6 +1179,14 @@ AstNode* Ast::createNodeNop () { return const_cast(&NopNode); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the AST nop node +//////////////////////////////////////////////////////////////////////////////// + +AstNode* Ast::getNodeNop () { + return const_cast(&NopNode); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief create an AST n-ary operator node //////////////////////////////////////////////////////////////////////////////// @@ -1655,6 +1663,11 @@ TopLevelAttributes Ast::getReferencedAttributes (AstNode const* node, AstNode* Ast::clone (AstNode const* node) { auto type = node->type; + if (type == NODE_TYPE_NOP) { + // nop node is a singleton + return const_cast(node); + } + auto copy = createNode(type); // special handling for certain node types diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index 1f4e7a16b4..57bf579183 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -594,6 +594,12 @@ namespace triagens { AstNode* createNodeNop (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the AST nop node +//////////////////////////////////////////////////////////////////////////////// + + static AstNode* getNodeNop (); + //////////////////////////////////////////////////////////////////////////////// /// @brief create an AST n-ary operator //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index e27d29b6dd..cdd05923df 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -1201,8 +1201,10 @@ bool AstNode::isFalse () const { } //////////////////////////////////////////////////////////////////////////////// -/// @brief whether or not a value node is of type attribute access that -/// refers to the specified variable reference +/// @brief whether or not a value node is of type attribute access that +/// refers to any variable reference +/// returns true if yes, and then also returns variable reference and array +/// of attribute names in the parameter passed by reference //////////////////////////////////////////////////////////////////////////////// bool AstNode::isAttributeAccessForVariable (std::pair>& result) const { @@ -1223,10 +1225,17 @@ bool AstNode::isAttributeAccessForVariable (std::pairtype == NODE_TYPE_EXPANSION); TRI_ASSERT(node->numMembers() >= 2); + // check if the expansion uses a projection. if yes, we cannot use an index for it + if (node->getMember(4) != Ast::getNodeNop()) { + // [* RETURN projection] + result.second.clear(); + return false; + } + if (! node->getMember(1)->isAttributeAccessForVariable(result)) { result.second.clear(); return false; diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index 915ad4f789..02271ab758 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -507,7 +507,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a value node is of type attribute access that -/// refers to a variable reference +/// refers to any variable reference //////////////////////////////////////////////////////////////////////////////// bool isAttributeAccessForVariable () const { @@ -530,8 +530,10 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief whether or not a value node is of type attribute access that -/// refers to the specified variable reference +/// @brief whether or not a value node is of type attribute access that +/// refers to any variable reference +/// returns true if yes, and then also returns variable reference and array +/// of attribute names in the parameter passed by reference //////////////////////////////////////////////////////////////////////////////// bool isAttributeAccessForVariable (std::pair>&) const; diff --git a/arangod/Aql/ConditionFinder.cpp b/arangod/Aql/ConditionFinder.cpp index 9ba19e58cb..5dfd983df0 100644 --- a/arangod/Aql/ConditionFinder.cpp +++ b/arangod/Aql/ConditionFinder.cpp @@ -143,6 +143,11 @@ bool ConditionFinder::before (ExecutionNode* en) { SortCondition sortCondition(_sorts, _variableDefinitions); if (condition->findIndexes(node, usedIndexes, sortCondition)) { + bool reverse = false; + if (sortCondition.isUnidirectional()) { + reverse = sortCondition.isDescending(); + } + TRI_ASSERT(! usedIndexes.empty()); std::cout << node->id() << " Number of indexes used: " << usedIndexes.size() << std::endl; // We either can find indexes for everything or findIndexes will clear out usedIndexes @@ -153,7 +158,8 @@ bool ConditionFinder::before (ExecutionNode* en) { node->collection(), node->outVariable(), usedIndexes, - condition.get() + condition.get(), + reverse )); condition.release(); diff --git a/arangod/Aql/IndexBlock.h b/arangod/Aql/IndexBlock.h index 0ed9c959de..0f1891b30c 100644 --- a/arangod/Aql/IndexBlock.h +++ b/arangod/Aql/IndexBlock.h @@ -33,7 +33,6 @@ #include "Aql/ExecutionBlock.h" #include "Aql/ExecutionNode.h" #include "Aql/IndexNode.h" -#include "Aql/RangeInfo.h" #include "Utils/AqlTransaction.h" #include "VocBase/shaped-json.h" @@ -87,7 +86,7 @@ namespace triagens { public: IndexBlock (ExecutionEngine* engine, - IndexNode const* ep); + IndexNode const* ep); ~IndexBlock (); @@ -161,47 +160,6 @@ namespace triagens { void sortConditions (); -//////////////////////////////////////////////////////////////////////////////// -/// @brief andCombineRangeInfoVecs: combine the arguments into a single vector, -/// by intersecting every pair of range infos and inserting them in the returned -/// value if the intersection is valid. -//////////////////////////////////////////////////////////////////////////////// - - std::vector andCombineRangeInfoVecs (std::vector const&, - std::vector const&) const; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief cartesian: form the cartesian product of the inner vectors. This is -/// required in case a dynamic bound evaluates to a list, then we have an -/// "and" condition containing an "or" condition, which we must then distribute. -//////////////////////////////////////////////////////////////////////////////// - - IndexOrCondition* cartesian (std::vector> const&) const; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief: subclass for comparing IndexAndConditions in _condition. Similar to -/// OurLessThan in the SortBlock -//////////////////////////////////////////////////////////////////////////////// - - class SortFunc { - public: - SortFunc (std::vector> const& prefix, - IndexOrCondition* condition, - bool reverse) - : _prefix(prefix), - _condition(condition), - _reverse(reverse) { - } - - bool operator() (size_t const&, - size_t const&) const; - - private: - std::vector> const& _prefix; - IndexOrCondition* _condition; - bool const _reverse; - }; - // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/IndexNode.cpp b/arangod/Aql/IndexNode.cpp index 0b3aa47576..07cff64237 100644 --- a/arangod/Aql/IndexNode.cpp +++ b/arangod/Aql/IndexNode.cpp @@ -67,6 +67,8 @@ void IndexNode::toJsonHelper (triagens::basics::Json& nodes, json("indexes", indexes); json("condition", _condition->toJson(TRI_UNKNOWN_MEM_ZONE)); + + json("reverse", triagens::basics::Json(_reverse)); // And add it: nodes(json); @@ -83,7 +85,7 @@ ExecutionNode* IndexNode::clone (ExecutionPlan* plan, // TODO: check if we need to clone _condition or if we can reuse it here auto c = new IndexNode(plan, _id, _vocbase, _collection, - outVariable, _indexes, _condition); + outVariable, _indexes, _condition, _reverse); cloneHelper(c, plan, withDependencies, withProperties); @@ -101,7 +103,8 @@ IndexNode::IndexNode (ExecutionPlan* plan, _collection(plan->getAst()->query()->collections()->get(JsonHelper::checkAndGetStringValue(json.json(), "collection"))), _outVariable(varFromJson(plan->getAst(), json, "outVariable")), _indexes(), - _condition(nullptr) { + _condition(nullptr), + _reverse(JsonHelper::checkAndGetBooleanValue(json.json(), "reverse")) { auto indexes = JsonHelper::checkAndGetObjectValue(json.json(), "indexes"); diff --git a/arangod/Aql/IndexNode.h b/arangod/Aql/IndexNode.h index c60a0f6e0c..51bd222c62 100644 --- a/arangod/Aql/IndexNode.h +++ b/arangod/Aql/IndexNode.h @@ -62,13 +62,15 @@ namespace triagens { Collection const* collection, Variable const* outVariable, std::vector indexes, - Condition const* condition) + Condition const* condition, + bool reverse) : ExecutionNode(plan, id), _vocbase(vocbase), _collection(collection), _outVariable(outVariable), _indexes(indexes), - _condition(condition) { + _condition(condition), + _reverse(reverse) { TRI_ASSERT(_vocbase != nullptr); TRI_ASSERT(_collection != nullptr); @@ -198,6 +200,12 @@ namespace triagens { Condition const* _condition; +//////////////////////////////////////////////////////////////////////////////// +/// @brief the index sort order - this is the same order for all indexes +//////////////////////////////////////////////////////////////////////////////// + + bool _reverse; + }; } // namespace triagens::aql diff --git a/arangod/Aql/SortCondition.cpp b/arangod/Aql/SortCondition.cpp index a5bd2ce5d1..f159737e04 100644 --- a/arangod/Aql/SortCondition.cpp +++ b/arangod/Aql/SortCondition.cpp @@ -40,10 +40,15 @@ using namespace triagens::aql; // --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the sort condition +//////////////////////////////////////////////////////////////////////////////// + SortCondition::SortCondition (std::vector> const& expressions) : _expressions(expressions), _unidirectional(true), - _onlyAttributeAccess(true) { + _onlyAttributeAccess(true), + _ascending(true) { size_t const n = _expressions.size(); @@ -80,11 +85,16 @@ SortCondition::SortCondition (std::vector> const } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the sort condition +//////////////////////////////////////////////////////////////////////////////// + SortCondition::SortCondition (std::vector> const& sorts, std::unordered_map const& variableDefinitions) : _expressions(), _unidirectional(true), - _onlyAttributeAccess(true) { + _onlyAttributeAccess(true), + _ascending(true) { size_t const n = sorts.size(); @@ -92,6 +102,9 @@ SortCondition::SortCondition (std::vector> const& so if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) { _unidirectional = false; } + if (i == 0) { + _ascending = sorts[i].second; + } bool handled = false; auto variableId = sorts[i].first; @@ -128,6 +141,13 @@ SortCondition::SortCondition (std::vector> const& so } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the sort condition +//////////////////////////////////////////////////////////////////////////////// + +SortCondition::~SortCondition () { +} + // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/SortCondition.h b/arangod/Aql/SortCondition.h index 8977e94c2b..243a05d8cb 100644 --- a/arangod/Aql/SortCondition.h +++ b/arangod/Aql/SortCondition.h @@ -54,13 +54,24 @@ namespace triagens { SortCondition (SortCondition const&) = delete; SortCondition& operator= (SortCondition const&) = delete; +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the sort condition +//////////////////////////////////////////////////////////////////////////////// + explicit SortCondition (std::vector> const&); +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the sort condition +//////////////////////////////////////////////////////////////////////////////// + SortCondition (std::vector> const&, std::unordered_map const&); - ~SortCondition () { - } +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the sort condition +//////////////////////////////////////////////////////////////////////////////// + + ~SortCondition (); // ----------------------------------------------------------------------------- // --SECTION-- public methods @@ -84,6 +95,26 @@ namespace triagens { return _unidirectional; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not all sort directions are ascending +/// note that the return value of this function is only meaningful if the +/// sort is unidirectional +//////////////////////////////////////////////////////////////////////////////// + + inline bool isAscending () const { + TRI_ASSERT(isUnidirectional()); + return _ascending; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not all sort directions are descending +/// this is the reverse of isAscending() +//////////////////////////////////////////////////////////////////////////////// + + inline bool isDescending () const { + return ! isAscending(); + } + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not there are fields //////////////////////////////////////////////////////////////////////////////// @@ -137,6 +168,13 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// bool _onlyAttributeAccess; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not all sorts are in ascending order. +/// this is only meaningful if the sort is unidirectional +//////////////////////////////////////////////////////////////////////////////// + + bool _ascending; }; }