From 31e02e42cb6e24a1d9eab1e8d4bf3be74a65168e Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Thu, 11 Sep 2014 14:28:38 +0200 Subject: [PATCH] Instanciate expressions for variable bounds. And various cleanups. --- arangod/Aql/Ast.cpp | 6 +-- arangod/Aql/Ast.h | 10 +---- arangod/Aql/ExecutionBlock.cpp | 66 ++++++++++++++++++++++++++++----- arangod/Aql/ExecutionBlock.h | 14 +++++++ arangod/Aql/ExecutionEngine.cpp | 8 ++-- arangod/Aql/ExecutionEngine.h | 16 +++++++- arangod/Aql/ExecutionNode.cpp | 3 +- arangod/Aql/ExecutionNode.h | 3 ++ arangod/Aql/OptimizerRules.cpp | 54 +++++++++++++++++---------- arangod/Aql/Parser.cpp | 7 +--- arangod/Aql/Query.cpp | 11 ++++-- arangod/Aql/Query.h | 16 ++++++++ 12 files changed, 156 insertions(+), 58 deletions(-) diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index ea32bd71c7..8f8e4f9dfa 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -30,7 +30,6 @@ #include "Aql/Ast.h" #include "Aql/Collection.h" #include "Aql/Executor.h" -#include "Aql/Parser.h" #include "BasicsC/tri-strings.h" #include "Utils/Exception.h" #include "VocBase/collection.h" @@ -55,10 +54,8 @@ AstNode const Ast::NopNode = { NODE_TYPE_NOP }; /// @brief create the AST //////////////////////////////////////////////////////////////////////////////// -Ast::Ast (Query* query, - Parser* parser) +Ast::Ast (Query* query) : _query(query), - _parser(parser), _nodes(), _scopes(), _variables(), @@ -68,7 +65,6 @@ Ast::Ast (Query* query, _writeCollection(nullptr) { TRI_ASSERT(_query != nullptr); - TRI_ASSERT(_parser != nullptr); _nodes.reserve(32); diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index 93987638e2..217b1e4a0e 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -43,7 +43,6 @@ namespace triagens { namespace aql { - class Parser; class Query; // ----------------------------------------------------------------------------- @@ -66,8 +65,7 @@ namespace triagens { /// @brief create the AST //////////////////////////////////////////////////////////////////////////////// - Ast (Query*, - Parser*); + Ast (Query*); //////////////////////////////////////////////////////////////////////////////// /// @brief destroy the AST @@ -603,12 +601,6 @@ namespace triagens { Query* _query; -//////////////////////////////////////////////////////////////////////////////// -/// @brief the query parser -//////////////////////////////////////////////////////////////////////////////// - - Parser* _parser; - //////////////////////////////////////////////////////////////////////////////// /// @brief all nodes created in the AST - will be used for freeing them later //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 1e4b6cdbe3..5b834751e7 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -782,20 +782,66 @@ size_t EnumerateCollectionBlock::skipSome (size_t atLeast, size_t atMost) { // ----------------------------------------------------------------------------- IndexRangeBlock::IndexRangeBlock (ExecutionEngine* engine, - IndexRangeNode const* ep) - : ExecutionBlock(engine, ep), - _collection(ep->_collection), - _posInDocs(0) { - /* - std::cout << "USING INDEX: " << ep->_index->_iid << ", " << - TRI_TypeNameIndex(ep->_index->_type) << "\n"; + IndexRangeNode const* en) + : ExecutionBlock(engine, en), + _collection(en->_collection), + _posInDocs(0), + _allBoundsConstant(true) { + + /* + std::cout << "USING INDEX: " << en->_index->_iid << ", " << + TRI_TypeNameIndex(en->_index->_type) << "\n"; */ - // TODO: detect whether all ranges are constant - // TODO: if not, instanciate expressions + + std::vector> const& orRanges = en->_ranges; + + TRI_ASSERT(orRanges.size() == 1); // OR expressions not yet implemented + + // Detect, whether all ranges are constant: + std::vector const& attrRanges = orRanges[0]; + for (auto r : attrRanges) { + _allBoundsConstant &= r.isConstant(); + } + + // instanciate expressions: + auto instanciateExpression = [&] (Json const& json) -> void { + auto a = new AstNode(engine->getQuery()->ast(), json); + // all new AstNodes are registered with the Ast in the Query + auto e = new Expression(engine->getQuery()->executor(), a); + try { + _allVariableBoundExpressions.push_back(e); + } + catch (...) { + delete e; + throw; + } + }; + + if (! _allBoundsConstant) { + try { + for (auto r : attrRanges) { + for (auto l : r._lows) { + instanciateExpression(l.bound()); + } + for (auto h : r._highs) { + instanciateExpression(h.bound()); + } + } + } + catch (...) { + for (auto e : _allVariableBoundExpressions) { + delete e; + } + throw; + } + } } IndexRangeBlock::~IndexRangeBlock () { - // TODO: free expressions + for (auto e : _allVariableBoundExpressions) { + delete e; + } + _allVariableBoundExpressions.clear(); } bool IndexRangeBlock::readIndex () { diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index 591950bb93..b4487f80c0 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -684,6 +684,20 @@ public: size_t _posInDocs; +//////////////////////////////////////////////////////////////////////////////// +/// @brief _allBoundsConstant, this indicates whether all given bounds +/// are constant +//////////////////////////////////////////////////////////////////////////////// + + bool _allBoundsConstant; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief _allBoundsConstant, this indicates whether all given bounds +/// are constant +//////////////////////////////////////////////////////////////////////////////// + + std::vector _allVariableBoundExpressions; + }; // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index b94df3ff73..8acb1b958d 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -44,11 +44,12 @@ using namespace triagens::aql; /// @brief create the engine //////////////////////////////////////////////////////////////////////////////// -ExecutionEngine::ExecutionEngine (AQL_TRANSACTION_V8* trx) +ExecutionEngine::ExecutionEngine (AQL_TRANSACTION_V8* trx, Query* query) : _stats(), _blocks(), _root(nullptr), - _trx(trx) { + _trx(trx), + _query(query) { _blocks.reserve(8); } @@ -220,8 +221,9 @@ struct Instanciator : public WalkerWorker { //////////////////////////////////////////////////////////////////////////////// ExecutionEngine* ExecutionEngine::instanciateFromPlan (AQL_TRANSACTION_V8* trx, + Query* query, ExecutionPlan* plan) { - auto engine = new ExecutionEngine(trx); + auto engine = new ExecutionEngine(trx, query); try { if (! plan->varUsageComputed()) { diff --git a/arangod/Aql/ExecutionEngine.h b/arangod/Aql/ExecutionEngine.h index a4e10eed44..c61743ca55 100644 --- a/arangod/Aql/ExecutionEngine.h +++ b/arangod/Aql/ExecutionEngine.h @@ -57,7 +57,7 @@ namespace triagens { /// @brief create the engine //////////////////////////////////////////////////////////////////////////////// - ExecutionEngine (AQL_TRANSACTION_V8* trx); + ExecutionEngine (AQL_TRANSACTION_V8* trx, Query* query); public: @@ -78,6 +78,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// static ExecutionEngine* instanciateFromPlan (AQL_TRANSACTION_V8*, + Query*, ExecutionPlan*); //////////////////////////////////////////////////////////////////////////////// @@ -97,6 +98,14 @@ namespace triagens { return _trx; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the query +//////////////////////////////////////////////////////////////////////////////// + + Query* getQuery () const { + return _query; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief getSome //////////////////////////////////////////////////////////////////////////////// @@ -188,6 +197,11 @@ namespace triagens { AQL_TRANSACTION_V8* _trx; +//////////////////////////////////////////////////////////////////////////////// +/// @brief a pointer to the query +//////////////////////////////////////////////////////////////////////////////// + + Query* _query; }; } diff --git a/arangod/Aql/ExecutionNode.cpp b/arangod/Aql/ExecutionNode.cpp index 2d14f54f5c..20616b048a 100644 --- a/arangod/Aql/ExecutionNode.cpp +++ b/arangod/Aql/ExecutionNode.cpp @@ -505,7 +505,8 @@ void EnumerateCollectionNode::getIndexesForIndexRangeNode } } -std::vector EnumerateCollectionNode::getIndicesOrdered (IndexMatchVec &attrs) const { +std::vector + EnumerateCollectionNode::getIndicesOrdered (IndexMatchVec &attrs) const { std::vector out; TRI_document_collection_t* document = _collection->documentCollection(); diff --git a/arangod/Aql/ExecutionNode.h b/arangod/Aql/ExecutionNode.h index 656c38a061..7bf10b9e12 100644 --- a/arangod/Aql/ExecutionNode.h +++ b/arangod/Aql/ExecutionNode.h @@ -880,12 +880,15 @@ namespace triagens { TRI_ASSERT(_collection != nullptr); TRI_ASSERT(_outVariable != nullptr); TRI_ASSERT(_index != nullptr); + /* std::cout << "Hallole" << std::endl; for (auto x : ranges) { + std::cout << "Or Entry:" << std::endl; for (auto y : x) { std::cout << y.toString() << std::endl; } } + */ } IndexRangeNode (Ast*, basics::Json const& base); diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index 5c40660bbb..3ff10094a2 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -786,7 +786,7 @@ int triagens::aql::useIndexRange (Optimizer* opt, /// @brief analyse the sortnode and its calculation nodes //////////////////////////////////////////////////////////////////////////////// -class sortAnalysis { +class SortAnalysis { using ECN = triagens::aql::EnumerateCollectionNode; typedef std::pair Range_IndexPair; @@ -807,31 +807,38 @@ public: /// @brief constructor; fetches the referenced calculation nodes and builds /// _sortNodeData for later use. //////////////////////////////////////////////////////////////////////////////// - sortAnalysis (SortNode * node) - : sortNodeID(node->id()) + + SortAnalysis (SortNode* node) + : sortNodeID(node->id()) { auto sortParams = node->getCalcNodePairs(); for (size_t n = 0; n < sortParams.size(); n++) { auto d = new sortNodeData; - d->ASC = sortParams[n].second; - d->calculationNodeID = sortParams[n].first->id(); + try { + d->ASC = sortParams[n].second; + d->calculationNodeID = sortParams[n].first->id(); - if (sortParams[n].first->getType() == EN::CALCULATION) { - auto cn = static_cast(sortParams[n].first); - auto oneSortExpression = cn->expression(); - - if (oneSortExpression->isAttributeAccess()) { - auto simpleExpression = oneSortExpression->getMultipleAttributes(); - d->variableName = simpleExpression.first; - d->attributevec = simpleExpression.second; + if (sortParams[n].first->getType() == EN::CALCULATION) { + auto cn = static_cast(sortParams[n].first); + auto oneSortExpression = cn->expression(); + + if (oneSortExpression->isAttributeAccess()) { + auto simpleExpression = oneSortExpression->getMultipleAttributes(); + d->variableName = simpleExpression.first; + d->attributevec = simpleExpression.second; + } } + _sortNodeData.push_back(d); + } + catch (...) { + delete d; + throw; } - _sortNodeData.push_back(d); } } - ~sortAnalysis () { + ~SortAnalysis () { for (auto x : _sortNodeData){ delete x; } @@ -840,6 +847,7 @@ public: //////////////////////////////////////////////////////////////////////////////// /// @brief checks the whether we only have simple calculation nodes //////////////////////////////////////////////////////////////////////////////// + bool isAnalyzeable () { if (_sortNodeData.size() == 0) { return false; @@ -874,6 +882,7 @@ public: /// @brief checks whether our calculation nodes reference variableName; /// @returns pair used for further processing with the indices. //////////////////////////////////////////////////////////////////////////////// + Range_IndexPair getAttrsForVariableName (std::string &variableName) { ECN::IndexMatchVec v; RangeInfoVec rangeInfo; @@ -883,17 +892,22 @@ public: return std::make_pair(v, rangeInfo); // for now, no mixed support. } } + // Collect the right data for the sorting: for (size_t j = 0; j < _sortNodeData.size(); j ++) { v.push_back(std::make_pair(_sortNodeData[j]->attributevec, _sortNodeData[j]->ASC)); - rangeInfo.push_back(std::vector()); } + // We only need one or-condition (because this is mandatory) which + // refers to 0 of the attributes: + rangeInfo.push_back(std::vector()); return std::make_pair(v, rangeInfo); } //////////////////////////////////////////////////////////////////////////////// -/// @brief removes the sortNode and its referenced Calculationnodes from the plan. +/// @brief removes the sortNode and its referenced Calculationnodes from +/// the plan. //////////////////////////////////////////////////////////////////////////////// + void removeSortNodeFromPlan (ExecutionPlan *newPlan) { newPlan->unlinkNode(newPlan->getNodeById(sortNodeID)); } @@ -904,7 +918,7 @@ class sortToIndexNode : public WalkerWorker { Optimizer* _opt; ExecutionPlan* _plan; - sortAnalysis* _sortNode; + SortAnalysis* _sortNode; Optimizer::RuleLevel _level; public: @@ -913,7 +927,7 @@ class sortToIndexNode : public WalkerWorker { sortToIndexNode (Optimizer* opt, ExecutionPlan* plan, - sortAnalysis* Node, + SortAnalysis* Node, Optimizer::RuleLevel level) : _opt(opt), _plan(plan), @@ -1036,7 +1050,7 @@ int triagens::aql::useIndexForSort (Optimizer* opt, = plan->findNodesOfType(triagens::aql::ExecutionNode::SORT, true); for (auto n : nodes) { auto thisSortNode = static_cast(n); - sortAnalysis node(thisSortNode); + SortAnalysis node(thisSortNode); if (node.isAnalyzeable()) { sortToIndexNode finder(opt, plan, &node, rule->level); thisSortNode->walk(&finder);/// todo auf der dependency anfangen diff --git a/arangod/Aql/Parser.cpp b/arangod/Aql/Parser.cpp index 8718ede726..e0cd3e5e94 100644 --- a/arangod/Aql/Parser.cpp +++ b/arangod/Aql/Parser.cpp @@ -43,7 +43,7 @@ using namespace triagens::aql; Parser::Parser (Query* query) : _query(query), - _ast(nullptr), + _ast(query->ast()), _scanner(nullptr), _buffer(query->queryString()), _remainingLength(query->queryLength()), @@ -51,8 +51,6 @@ Parser::Parser (Query* query) _marker(nullptr), _stack() { - _ast = new Ast(query, this); - _stack.reserve(16); } @@ -61,9 +59,6 @@ Parser::Parser (Query* query) //////////////////////////////////////////////////////////////////////////////// Parser::~Parser () { - if (_ast != nullptr) { - delete _ast; - } } // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 6865389eeb..188c81fc47 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -67,10 +67,13 @@ Query::Query (TRI_vocbase_t* vocbase, _bindParameters(bindParameters), _options(options), _collections(vocbase), - _strings() { + _strings(), + _ast(nullptr) { TRI_ASSERT(_vocbase != nullptr); + _ast = new Ast(this); + _strings.reserve(32); } @@ -86,10 +89,12 @@ Query::Query (TRI_vocbase_t* vocbase, _bindParameters(nullptr), _options(nullptr), _collections(vocbase), - _strings() { + _strings(), + _ast(nullptr) { TRI_ASSERT(_vocbase != nullptr); + _ast = new Ast(this); _strings.reserve(32); } @@ -278,7 +283,7 @@ QueryResult Query::execute () { triagens::basics::Json stats; try { - auto engine = ExecutionEngine::instanciateFromPlan(&trx, plan); + auto engine = ExecutionEngine::instanciateFromPlan(&trx, this, plan); try { AqlItemBlock* value; diff --git a/arangod/Aql/Query.h b/arangod/Aql/Query.h index e687a9a9cc..2163ab404c 100644 --- a/arangod/Aql/Query.h +++ b/arangod/Aql/Query.h @@ -48,6 +48,7 @@ namespace triagens { class Expression; struct Variable; struct AstNode; + class Ast; // ----------------------------------------------------------------------------- // --SECTION-- public types @@ -155,6 +156,14 @@ namespace triagens { return _queryLength; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief getter for _ast +//////////////////////////////////////////////////////////////////////////////// + + Ast* ast () const { + return _ast; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief extract a region from the query //////////////////////////////////////////////////////////////////////////////// @@ -291,6 +300,13 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// std::vector _strings; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief _ast, we need an ast to manage the memory for AstNodes, even +/// if we do not have a parser, because AstNodes occur in plans and engines +//////////////////////////////////////////////////////////////////////////////// + + Ast* _ast; }; }