diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index c7c7857ee4..cbb6d9119c 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -64,7 +64,7 @@ AstNode::~AstNode () { /// the caller is responsible for freeing the JSON later //////////////////////////////////////////////////////////////////////////////// -TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone) { +TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone) const { TRI_json_t* node = TRI_CreateArrayJson(zone); if (node == nullptr) { @@ -151,7 +151,7 @@ TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone) { //////////////////////////////////////////////////////////////////////////////// void AstNode::toJson (TRI_json_t* json, - TRI_memory_zone_t* zone) { + TRI_memory_zone_t* zone) const { TRI_ASSERT(TRI_IsListJson(json)); TRI_json_t* node = toJson(zone); diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index 38d698d453..7f63db694a 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -165,7 +165,7 @@ namespace triagens { /// the caller is responsible for freeing the JSON later //////////////////////////////////////////////////////////////////////////////// - struct TRI_json_s* toJson (TRI_memory_zone_t*); + struct TRI_json_s* toJson (TRI_memory_zone_t*) const; //////////////////////////////////////////////////////////////////////////////// /// @brief adds a JSON representation of the node to the JSON list specified @@ -173,7 +173,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// void toJson (TRI_json_t*, - TRI_memory_zone_t*); + TRI_memory_zone_t*) const; //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a value node is of numeric type diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 12a707310e..164c9efd6b 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -26,6 +26,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "Aql/ExecutionBlock.h" +#include "Utils/Exception.h" using namespace triagens::basics; using namespace triagens::arango; @@ -82,8 +83,7 @@ ExecutionBlock* ExecutionBlock::instanciatePlan (ExecutionPlan const* ep) { break; } default: { - TRI_ASSERT(false); - break; + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); } } vector deps = ep->getDependencies(); @@ -117,26 +117,26 @@ int ExecutionBlock::staticAnalysisRecursion ( _depth++; curVar = 0; auto p = static_cast(_exePlan); - varTab.insert(make_pair(p->_outVarNumber, VarDefPlace(_depth, 0))); + varTab.insert(make_pair(p->_outVariable->id, VarDefPlace(_depth, 0))); break; } case ExecutionPlan::ENUMERATE_LIST: { _depth++; curVar = 0; auto p = static_cast(_exePlan); - varTab.insert(make_pair(p->_outVarNumber, VarDefPlace(_depth, 0))); + varTab.insert(make_pair(p->_outVariable->id, VarDefPlace(_depth, 0))); break; } case ExecutionPlan::CALCULATION: { curVar++; auto p = static_cast(_exePlan); - varTab.insert(make_pair(p->_varNumber, VarDefPlace(_depth, curVar))); + varTab.insert(make_pair(p->_outVariable->id, VarDefPlace(_depth, curVar))); break; } case ExecutionPlan::PROJECTION: { curVar++; auto p = static_cast(_exePlan); - varTab.insert(make_pair(p->_outVar, VarDefPlace(_depth, curVar))); + varTab.insert(make_pair(p->_outVariable->id, VarDefPlace(_depth, curVar))); break; } // TODO: potentially more cases diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index b30ebe58fe..259420b4e1 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -177,15 +177,9 @@ void EnumerateCollectionPlan::toJsonHelper (std::map& index } // Now put info about vocbase and cid in there - if (_vocbase == nullptr) { - json("vocbase", Json("")); - } - else { - json("vocbase", Json(_vocbase->_name)); - } - json("collection", Json(_collname)) - ("outVarNumber", Json(static_cast(_outVarNumber))) - ("outVarName", Json(_outVarName)); + json("database", Json(_vocbase->_name)) + ("collection", Json(_collname)) + ("outVariable", _outVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -208,11 +202,8 @@ void EnumerateListPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - json("varNumber", Json(static_cast(_varNumber))) - ("varName", Json(_varName)) - ("outVarNumber", Json(static_cast(_outVarNumber))) - ("outVarName", Json(_outVarName)); - + json("inVariable", _inVariable->toJson()) + ("outVariable", _outVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -260,9 +251,9 @@ void CalculationPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - json("varNumber", Json(static_cast(_varNumber))) - ("varName", Json(_varName)) - ("expression", _expression->toJson(TRI_UNKNOWN_MEM_ZONE)); + + json("expression", _expression->toJson(TRI_UNKNOWN_MEM_ZONE)) + ("outVariable", _outVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -285,9 +276,8 @@ void SubqueryPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - json("varNumber", Json(static_cast(_varNumber))) - ("varName", Json(_varName)) - ("subquery", _subquery->toJson(TRI_UNKNOWN_MEM_ZONE)); + json("subquery", _subquery->toJson(TRI_UNKNOWN_MEM_ZONE)) + ("outVariable", _outVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -314,10 +304,9 @@ void ProjectionPlan::toJsonHelper (std::map& indexTab, for (auto it = _keepAttributes.begin(); it != _keepAttributes.end(); ++it) { vec(Json(*it)); } - json("inVarNumber", Json(static_cast(_inVar))) - ("inVarName", Json(_inVarName)) - ("outVarNumber", Json(static_cast(_outVar))) - ("outVarName", Json(_outVarName)) + + json("inVariable", _inVariable->toJson()) + ("outVariable", _outVariable->toJson()) ("keepAttributes", vec); // And add it: @@ -341,9 +330,8 @@ void FilterPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - // Now put info about offset and limit in - json("varName", Json(_varName)) - ("varNumber", Json(static_cast(_varNumber))); + + json("inVariable", _inVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -366,21 +354,14 @@ void SortPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - Json numbers(Json::List, _varNumbers.size()); - for (auto it = _varNumbers.begin(); it != _varNumbers.end(); ++it) { - numbers(Json(static_cast(*it))); + Json values(Json::List, _elements.size()); + for (auto it = _elements.begin(); it != _elements.end(); ++it) { + Json element(Json::Array); + element("inVariable", (*it).first->toJson()) + ("ascending", Json((*it).second)); + values(element); } - Json names(Json::List, _varNames.size()); - for (auto it = _varNames.begin(); it != _varNames.end(); ++it) { - names(Json(*it)); - } - Json vec(Json::List, _sortAscending.size()); - for (auto it = _sortAscending.begin(); it != _sortAscending.end(); ++it) { - vec(Json(*it)); - } - json("varNumbers", numbers) - ("varNames", names) - ("sortAscending", vec); + json("elements", values); // And add it: int len = static_cast(nodes.size()); @@ -403,18 +384,20 @@ void AggregateOnUnsortedPlan::toJsonHelper (std::map& index if (json.isEmpty()) { return; } - Json numbers(Json::List, _varNumbers.size()); - for (auto it = _varNumbers.begin(); it != _varNumbers.end(); ++it) { - numbers(Json(static_cast(*it))); + + Json values(Json::List, _aggregateVariables.size()); + for (auto it = _aggregateVariables.begin(); it != _aggregateVariables.end(); ++it) { + Json variable(Json::Array); + variable("outVariable", (*it).first->toJson()) + ("inVariable", (*it).second->toJson()); + values(variable); } - Json names(Json::List, _varNames.size()); - for (auto it = _varNames.begin(); it != _varNames.end(); ++it) { - names(Json(*it)); + json("aggregates", values); + + // output variable might be empty + if (_outVariable != nullptr) { + json("outVariable", _outVariable->toJson()); } - json("varNumbers", numbers) - ("varNames", names) - ("outVarNumber", Json(static_cast(_outVarNumber))) - ("outVarName", Json(_outVarName)); // And add it: int len = static_cast(nodes.size()); @@ -437,8 +420,8 @@ void RootPlan::toJsonHelper (std::map& indexTab, if (json.isEmpty()) { return; } - json("varNumber", Json(static_cast(_varNumber))) - ("varName" , Json(_varName)); + + json("inVariable", _inVariable->toJson()); // And add it: int len = static_cast(nodes.size()); @@ -446,246 +429,6 @@ void RootPlan::toJsonHelper (std::map& indexTab, indexTab.insert(make_pair(this, len)); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief test function -//////////////////////////////////////////////////////////////////////////////// - -using namespace triagens::basics; - -using namespace std; - -class MyWorker2 : public triagens::aql::ExecutionPlan::WalkerWorker { - public: - int count; - MyWorker2 () : count(0) {}; - ~MyWorker2 () {}; - void before (triagens::aql::ExecutionPlan* ep) { - std::cout << "Before node of type " << ep->getTypeString() - << std::endl; - count++; - } - void after (triagens::aql::ExecutionPlan* ep) { - std::cout << "After node of type " << ep->getTypeString() - << std::endl; - } -}; - -void testExecutionPlans () { - Json a(12); - Json b(Json::Array); - b("a",a); - std::cout << b.toString() << std::endl; - std::cout << a.toString() << std::endl; - std::cout << "Got here" << std::endl; - - auto ec = new EnumerateCollectionPlan(nullptr, "guck", 1, "X"); - Json jjj(ec->toJson()); - cout << jjj.toString() << endl; - auto li = new LimitPlan(12, 17); - li->addDependency(ec); - jjj = li->toJson(); - cout << jjj.toString() << endl; - - TRI_json_t* json = Json(12); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(true); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(Json::Null); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(Json::String); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(Json::List); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(Json::Array); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - json = Json(Json::Array, 10) - ("myinteger", Json(12)) - ("mystring", Json("hallo")) - ("mybool", Json(false)) - ("mynull", Json(Json::Null)) - ("mylist", Json(Json::List, 3) - (Json(1)) - (Json(2)) - (Json(3))) - ("myarray", Json(Json::Array, 2) - ("a",Json("hallo")) - ("b",Json(13))); - cout << JsonHelper::toString(json) << endl; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - Json j(Json::Array); - j("a", Json(12)) - ("b", Json(true)) - ("c", Json(Json::List) - (Json(1))(Json(2))(Json(3))) - ("d", Json(Json::Array) - ("x", Json(12)) - ("y", Json(true))); - cout << j.toString() << endl; - - // We expect to see exactly two copies here: - Json jjjj = j.copy(); // create an explicit copy - Json jj(12); - - cout << "Before assignment" << jj.toString() << endl; - jj = j; // this steals the pointer from j - - cout << jjjj.toString(); - cout << jj.toString(); - - Json k = jj.get("c"); - Json l = k.at(2); - - cout << l.toString() << endl; - - cout << "and now a complete test" << endl << endl; - - // Here we want to build the unoptimised plan for: - // - // LET A = [1,2,3] - // FOR g IN guck - // FILTER g.name == "Wurst" - // SORT g.vorname - // LIMIT 2, 10 - // FOR i IN A - // LET X = { "vorname": g.vorname, "addresse": g.addresse, - // "nr": i*2 } - // RETURN X - // - // - { - AstNode* a; - AstNode* b; - AstNode* c; - ExecutionPlan* e; - ExecutionPlan* n; - - // Singleton - e = new SingletonPlan(); - - // LET A = [1,2,3] - a = new AstNode(NODE_TYPE_LIST); - b = new AstNode(NODE_TYPE_VALUE); - b->setValueType(VALUE_TYPE_INT); - b->setIntValue(1); - a->addMember(b); - b = new AstNode(NODE_TYPE_VALUE); - b->setValueType(VALUE_TYPE_INT); - b->setIntValue(2); - a->addMember(b); - b = new AstNode(NODE_TYPE_VALUE); - b->setValueType(VALUE_TYPE_INT); - b->setIntValue(3); - a->addMember(b); - n = new CalculationPlan(new AqlExpression(a), 1, "A"); - n->addDependency(e); - e = n; - - // FOR g IN guck - n = new EnumerateCollectionPlan(nullptr, "guck", 2, "g"); - n->addDependency(e); - e = n; - - // FILTER g.name == "Wurst" - a = new AstNode(NODE_TYPE_OPERATOR_BINARY_EQ); - b = new AstNode(NODE_TYPE_VALUE); - b->setValueType(VALUE_TYPE_STRING); - b->setStringValue("g.name"); - a->addMember(b); - b = new AstNode(NODE_TYPE_VALUE); - b->setValueType(VALUE_TYPE_STRING); - b->setStringValue("Wurst"); - a->addMember(b); - n = new CalculationPlan(new AqlExpression(a), 2, "_1"); - n->addDependency(e); - e = n; - n = new FilterPlan(2, "_1"); - n->addDependency(e); - e = n; - - // SORT g.vorname - a = new AstNode(NODE_TYPE_VALUE); - a->setValueType(VALUE_TYPE_STRING); - a->setStringValue("g.vorname"); - n = new CalculationPlan(new AqlExpression(a), 3, "_2"); - n->addDependency(e); - e = n; - std::vector vars; - std::vector names; - std::vector asc; - vars.push_back(3); - names.push_back(string("_2")); - asc.push_back(true); - n = new SortPlan(vars, names, asc); - n->addDependency(e); - e = n; - - // LIMIT 2, 10 - n = new LimitPlan(2, 10); - n->addDependency(e); - e = n; - - // FOR i in A - n = new EnumerateListPlan(1, "A", 2, "i"); - n->addDependency(e); - e = n; - - // LET X = {"vorname": g.vorname, "addresse": g.addresse, "nr": i*2} - a = new AstNode(NODE_TYPE_ARRAY); - b = new AstNode(NODE_TYPE_ARRAY_ELEMENT); - b->setValueType(VALUE_TYPE_STRING); - b->setStringValue("vorname"); - c = new AstNode(NODE_TYPE_VALUE); - c->setValueType(VALUE_TYPE_STRING); - c->setStringValue("g.vorname"); - b->addMember(c); - a->addMember(b); - b = new AstNode(NODE_TYPE_ARRAY_ELEMENT); - b->setValueType(VALUE_TYPE_STRING); - b->setStringValue("adresse"); - c = new AstNode(NODE_TYPE_VALUE); - c->setValueType(VALUE_TYPE_STRING); - c->setStringValue("g.addresse"); - b->addMember(c); - a->addMember(b); - b = new AstNode(NODE_TYPE_ARRAY_ELEMENT); - b->setValueType(VALUE_TYPE_STRING); - b->setStringValue("nr"); - c = new AstNode(NODE_TYPE_VALUE); - c->setValueType(VALUE_TYPE_STRING); - c->setStringValue("i*2"); - b->addMember(c); - a->addMember(b); - n = new CalculationPlan(new AqlExpression(a), 4, "X"); - n->addDependency(e); - e = n; - - // RETURN X - n = new RootPlan(4, "X"); - n->addDependency(e); - e = n; - - cout << e->toJson().toString() << endl; - MyWorker2 w; - e->walk(w); - cout << "Count is: " << w.count << endl; - - delete e; - } -} - // Local Variables: // mode: outline-minor // outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index d2f92ffd46..34f5d1ceb7 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -34,6 +34,7 @@ #include #include +#include "Aql/Expression.h" #include "Aql/Variable.h" #include "Aql/Types.h" @@ -336,10 +337,12 @@ namespace triagens { EnumerateCollectionPlan (TRI_vocbase_t* vocbase, std::string collname, - VariableId outVarNumber, - std::string outVarName) + Variable const* outVariable) : ExecutionPlan(), _vocbase(vocbase), _collname(collname), - _outVarNumber(outVarNumber), _outVarName(outVarName) { + _outVariable(outVariable) { + + TRI_ASSERT(_vocbase != nullptr); + TRI_ASSERT(_outVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -371,8 +374,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new EnumerateCollectionPlan(_vocbase, _collname, - _outVarNumber, _outVarName); + auto c = new EnumerateCollectionPlan(_vocbase, _collname, _outVariable); cloneDependencies(c); return static_cast(c); } @@ -396,16 +398,10 @@ namespace triagens { std::string _collname; //////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarNumber, output variable +/// @brief output variable //////////////////////////////////////////////////////////////////////////////// - VariableId _outVarNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _outVarName; + Variable const* _outVariable; }; @@ -428,10 +424,12 @@ namespace triagens { public: - EnumerateListPlan (VariableId varNumber, std::string varName, - VariableId outVarNumber, std::string outVarName) - : ExecutionPlan(), _varNumber(varNumber), _varName(varName), - _outVarNumber(outVarNumber), _outVarName(outVarName) { + EnumerateListPlan (Variable const* inVariable, + Variable const* outVariable) + : ExecutionPlan(), _inVariable(inVariable), _outVariable(outVariable) { + + TRI_ASSERT(_inVariable != nullptr); + TRI_ASSERT(_outVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -463,8 +461,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new EnumerateListPlan(_varNumber, _varName, - _outVarNumber, _outVarName); + auto c = new EnumerateListPlan(_inVariable, _outVariable); cloneDependencies(c); return static_cast(c); } @@ -476,28 +473,16 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumber, input variable +/// @brief input variable to read from //////////////////////////////////////////////////////////////////////////////// - VariableId _varNumber; + Variable const* _inVariable; //////////////////////////////////////////////////////////////////////////////// -/// @brief _varName, name of variable to read from +/// @brief output variable to write to //////////////////////////////////////////////////////////////////////////////// - std::string _varName; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarNumber, output variable -//////////////////////////////////////////////////////////////////////////////// - - VariableId _outVarNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _outVarName; + Variable const* _outVariable; }; @@ -593,14 +578,14 @@ namespace triagens { public: - ProjectionPlan (VariableId inVar, - std::string inVarName, - VariableId outVar, - std::string outVarName, + ProjectionPlan (Variable const* inVariable, + Variable const* outVariable, std::vector keepAttributes) - : ExecutionPlan(), _inVar(inVar), _inVarName(inVarName), - _outVar(outVar), _outVarName(outVarName), + : ExecutionPlan(), _inVariable(inVariable), _outVariable(outVariable), _keepAttributes(keepAttributes) { + + TRI_ASSERT(inVariable != nullptr); + TRI_ASSERT(outVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -632,8 +617,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new ProjectionPlan(_inVar, _inVarName, _outVar, _outVarName, - _keepAttributes); + auto c = new ProjectionPlan(_inVariable, _outVariable, _keepAttributes); cloneDependencies(c); return static_cast(c); } @@ -645,28 +629,16 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief input variable +/// @brief input variable to read from //////////////////////////////////////////////////////////////////////////////// - VariableId _inVar; + Variable const* _inVariable; //////////////////////////////////////////////////////////////////////////////// -/// @brief _inVarName, name of variable to read from +/// @brief output variable to write to //////////////////////////////////////////////////////////////////////////////// - std::string _inVarName; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief output variable -//////////////////////////////////////////////////////////////////////////////// - - VariableId _outVar; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _outVarName; + Variable const* _outVariable; //////////////////////////////////////////////////////////////////////////////// /// @brief vector of attributes to leave in the object @@ -695,10 +667,11 @@ namespace triagens { /// @brief constructor //////////////////////////////////////////////////////////////////////////////// - CalculationPlan (AqlExpression* expr, VariableId varNumber, - std::string varName) - : ExecutionPlan(), _expression(expr), _varNumber(varNumber), - _varName(varName) { + CalculationPlan (Expression* expr, Variable const* outVariable) + : ExecutionPlan(), _expression(expr), _outVariable(outVariable) { + + TRI_ASSERT(_expression != nullptr); + TRI_ASSERT(_outVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -740,11 +713,19 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new CalculationPlan(_expression->clone(), _varNumber, _varName); + auto c = new CalculationPlan(_expression->clone(), _outVariable); cloneDependencies(c); return static_cast(c); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return out variable +//////////////////////////////////////////////////////////////////////////////// + + Variable const* outVariable () const { + return _outVariable; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief private data //////////////////////////////////////////////////////////////////////////////// @@ -755,19 +736,13 @@ namespace triagens { /// @brief we need to have an expression and where to write the result //////////////////////////////////////////////////////////////////////////////// - AqlExpression* _expression; + Expression* _expression; //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumber, global number of variable to write to +/// @brief output variable to write to //////////////////////////////////////////////////////////////////////////////// - VariableId _varNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _varName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _varName; + Variable const* _outVariable; }; @@ -790,10 +765,11 @@ namespace triagens { public: - SubqueryPlan (ExecutionPlan* subquery, VariableId varNumber, - std::string varName) - : ExecutionPlan(), _subquery(subquery), _varNumber(varNumber), - _varName(varName) { + SubqueryPlan (ExecutionPlan* subquery, Variable const* outVariable) + : ExecutionPlan(), _subquery(subquery), _outVariable(outVariable) { + + TRI_ASSERT(_subquery != nullptr); + TRI_ASSERT(_outVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -825,7 +801,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new SubqueryPlan(_subquery->clone(), _varNumber, _varName); + auto c = new SubqueryPlan(_subquery->clone(), _outVariable); cloneDependencies(c); return static_cast(c); } @@ -851,16 +827,10 @@ namespace triagens { ExecutionPlan* _subquery; //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumber, global number of variable to write to +/// @brief variable to write to //////////////////////////////////////////////////////////////////////////////// - VariableId _varNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _varName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _varName; + Variable const* _outVariable; }; @@ -883,8 +853,10 @@ namespace triagens { public: - FilterPlan (VariableId varNumber, std::string varName) - : ExecutionPlan(), _varNumber(varNumber), _varName(varName) { + FilterPlan (Variable const* inVariable) + : ExecutionPlan(), _inVariable(inVariable) { + + TRI_ASSERT(_inVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -916,7 +888,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new FilterPlan(_varNumber, _varName); + auto c = new FilterPlan(_inVariable); cloneDependencies(c); return static_cast(c); } @@ -928,16 +900,10 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumber, input variable +/// @brief input variable to read from //////////////////////////////////////////////////////////////////////////////// - VariableId _varNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _varName, name of variable to read from -//////////////////////////////////////////////////////////////////////////////// - - std::string _varName; + Variable const* _inVariable; }; @@ -960,11 +926,8 @@ namespace triagens { public: - SortPlan (std::vector varNumbers, - std::vector varNames, - std::vector sortAscending) - : ExecutionPlan(), _varNumbers(varNumbers), _varNames(varNames), - _sortAscending(sortAscending) { + SortPlan (std::vector> elements) + : ExecutionPlan(), _elements(elements) { } //////////////////////////////////////////////////////////////////////////////// @@ -996,7 +959,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new SortPlan(_varNumbers, _varNames, _sortAscending); + auto c = new SortPlan(_elements); cloneDependencies(c); return static_cast(c); } @@ -1008,22 +971,11 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumbers, input variables for sorting +/// @brief pairs, consisting of variable and sort direction +/// (true = ascending | false = descending) //////////////////////////////////////////////////////////////////////////////// - std::vector _varNumbers; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _varNames, name of variables for sorting -//////////////////////////////////////////////////////////////////////////////// - - std::vector _varNames; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief vector of attributes to sort by -//////////////////////////////////////////////////////////////////////////////// - - std::vector _sortAscending; + std::vector> _elements; }; @@ -1047,12 +999,9 @@ namespace triagens { public: - AggregateOnUnsortedPlan (std::vector varNumbers, - std::vector varNames, - VariableId outVarNumber, - std::string outVarName) - : ExecutionPlan(), _varNumbers(varNumbers), _varNames(varNames), - _outVarNumber(outVarNumber), _outVarName(outVarName) { + AggregateOnUnsortedPlan (std::vector> aggregateVariables, + Variable const* outVariable) + : ExecutionPlan(), _aggregateVariables(aggregateVariables), _outVariable(outVariable) { } //////////////////////////////////////////////////////////////////////////////// @@ -1084,8 +1033,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new AggregateOnUnsortedPlan(_varNumbers, _varNames, - _outVarNumber, _outVarName); + auto c = new AggregateOnUnsortedPlan(_aggregateVariables, _outVariable); cloneDependencies(c); return static_cast(c); } @@ -1097,28 +1045,16 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNumbers, input variables for the aggregation +/// @brief input/output variables for the aggregation (out = in) //////////////////////////////////////////////////////////////////////////////// - std::vector _varNumbers; + std::vector> _aggregateVariables; //////////////////////////////////////////////////////////////////////////////// -/// @brief _varNames, name of variables for the aggregation +/// @brief output variable to write to (might be null) //////////////////////////////////////////////////////////////////////////////// - std::vector _varNames; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief output variable -//////////////////////////////////////////////////////////////////////////////// - - VariableId _outVarNumber; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief _outVarName, name of variable to write to -//////////////////////////////////////////////////////////////////////////////// - - std::string _outVarName; + Variable const* _outVariable; }; @@ -1142,8 +1078,10 @@ namespace triagens { public: - RootPlan (VariableId varNumber, std::string varName) - : ExecutionPlan(), _varNumber(varNumber), _varName(varName) { + RootPlan (Variable const* inVariable) + : ExecutionPlan(), _inVariable(inVariable) { + + TRI_ASSERT(_inVariable != nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -1175,7 +1113,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// virtual ExecutionPlan* clone () const { - auto c = new RootPlan(_varNumber, _varName); + auto c = new RootPlan(_inVariable); cloneDependencies(c); return static_cast(c); } @@ -1186,9 +1124,7 @@ namespace triagens { private: - VariableId _varNumber; - - std::string _varName; + Variable const* _inVariable; }; } // namespace triagens::aql diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp new file mode 100644 index 0000000000..0cdeace6d9 --- /dev/null +++ b/arangod/Aql/Expression.cpp @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Aql, expression +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "Aql/Expression.h" +#include "Aql/Types.h" +#include "Aql/V8Executor.h" +#include "Utils/Exception.h" + +using namespace triagens::aql; + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the expression +//////////////////////////////////////////////////////////////////////////////// + +Expression::Expression (V8Executor* executor, + AstNode const* node) + : _executor(executor), + _node(node) { + + TRI_ASSERT(_executor != nullptr); + TRI_ASSERT(_node != nullptr); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the expression +//////////////////////////////////////////////////////////////////////////////// + +Expression::~Expression () { +} + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief execute the expression +//////////////////////////////////////////////////////////////////////////////// + +AqlValue* Expression::execute (AqlItem* item) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + return nullptr; +} + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" +// End: diff --git a/arangod/Aql/Expression.h b/arangod/Aql/Expression.h new file mode 100644 index 0000000000..f58b32bb91 --- /dev/null +++ b/arangod/Aql/Expression.h @@ -0,0 +1,133 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief AQL, expression +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-2014 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Max Neunhoeffer +/// @author Copyright 2014, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_AQL_EXPRESSION_H +#define ARANGODB_AQL_EXPRESSION_H 1 + +#include "Basics/Common.h" +#include "Aql/AstNode.h" +#include "Basics/JsonHelper.h" + +namespace triagens { + namespace aql { + + struct AqlItem; + struct AqlValue; + class V8Executor; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief AqlExpression, used in execution plans and execution blocks +//////////////////////////////////////////////////////////////////////////////// + + class Expression { + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors +// ----------------------------------------------------------------------------- + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructor, using an AST start node +//////////////////////////////////////////////////////////////////////////////// + + Expression (V8Executor*, + AstNode const*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destructor +//////////////////////////////////////////////////////////////////////////////// + + ~Expression (); + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the underlying AST node +//////////////////////////////////////////////////////////////////////////////// + + inline AstNode const* node () { + return _node; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief clone the expression, needed to clone execution plans +//////////////////////////////////////////////////////////////////////////////// + + Expression* clone () { + // We do not need to copy the _ast, since it is managed by the + // query object and the memory management of the ASTs + return new Expression(_executor, _node); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a Json representation of the expression +//////////////////////////////////////////////////////////////////////////////// + + triagens::basics::Json toJson (TRI_memory_zone_t* zone) const { + return triagens::basics::Json(zone, _node->toJson(zone)); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief execute the expression +//////////////////////////////////////////////////////////////////////////////// + + AqlValue* execute (AqlItem*); + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- + + private: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the V8 executor +//////////////////////////////////////////////////////////////////////////////// + + V8Executor* _executor; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief the AST node that contains the expression to execute +//////////////////////////////////////////////////////////////////////////////// + + // do we need a (possibly empty) subquery entry here? + AstNode const* _node; + + }; + + } // namespace triagens::aql +} // namespace triagens + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: + diff --git a/arangod/Aql/Parser.cpp b/arangod/Aql/Parser.cpp index 5e2959a355..a95cd061f4 100644 --- a/arangod/Aql/Parser.cpp +++ b/arangod/Aql/Parser.cpp @@ -29,6 +29,7 @@ #include "Aql/Parser.h" #include "Aql/AstNode.h" +#include "Aql/QueryResult.h" using namespace triagens::aql; @@ -107,7 +108,7 @@ bool Parser::configureWriteQuery (QueryType type, /// @brief parse the query //////////////////////////////////////////////////////////////////////////////// -ParseResult Parser::parse () { +QueryResult Parser::parse () { // start main scope auto scopes = _ast->scopes(); scopes->start(AQL_SCOPE_MAIN); @@ -134,7 +135,7 @@ ParseResult Parser::parse () { TRI_ASSERT(scopes->numActive() == 0); - ParseResult result; + QueryResult result; result.collectionNames = _ast->collectionNames(); result.bindParameters = _ast->bindParameters(); result.json = _ast->toJson(TRI_UNKNOWN_MEM_ZONE); diff --git a/arangod/Aql/Parser.h b/arangod/Aql/Parser.h index 4678c28f90..942517c31c 100644 --- a/arangod/Aql/Parser.h +++ b/arangod/Aql/Parser.h @@ -43,6 +43,7 @@ namespace triagens { struct AstNode; class Query; + struct QueryResult; class Parser; } } @@ -204,7 +205,7 @@ namespace triagens { /// @brief parse the query //////////////////////////////////////////////////////////////////////////////// - ParseResult parse (); + QueryResult parse (); //////////////////////////////////////////////////////////////////////////////// /// @brief register a parse error, position is specified as line / column diff --git a/arangod/Aql/PlanGenerator.cpp b/arangod/Aql/PlanGenerator.cpp index 032cd99e48..c63c032768 100644 --- a/arangod/Aql/PlanGenerator.cpp +++ b/arangod/Aql/PlanGenerator.cpp @@ -31,6 +31,7 @@ #include "Aql/Ast.h" #include "Aql/AstNode.h" #include "Aql/ExecutionPlan.h" +#include "Aql/Expression.h" #include "Aql/Query.h" #include "Aql/Variable.h" #include "Utils/Exception.h" @@ -79,6 +80,30 @@ ExecutionPlan* PlanGenerator::fromAst (Ast const* ast) { // --SECTION-- private functions // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a calculation node for an arbitrary expression +//////////////////////////////////////////////////////////////////////////////// + +CalculationPlan* PlanGenerator::createTemporaryCalculation (Ast const* ast, + AstNode const* expression) { + // generate a temporary variable + auto out = ast->variables()->createTemporaryVariable(); + TRI_ASSERT(out != nullptr); + + // generate a temporary calculation node + auto expr = new Expression(ast->query()->executor(), const_cast(expression)); + + try { + return new CalculationPlan(expr, out); + } + catch (...) { + // prevent memleak + delete expr; + throw; + // no need to delete "out" as this is automatically freed by the variables management + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief adds "previous" as dependency to "plan", returns "plan" //////////////////////////////////////////////////////////////////////////////// @@ -123,29 +148,20 @@ ExecutionPlan* PlanGenerator::fromNodeFor (Ast const* ast, if (expression->type == NODE_TYPE_COLLECTION) { // second operand is a collection char const* collectionName = expression->getStringValue(); - plan = new EnumerateCollectionPlan(ast->query()->vocbase(), std::string(collectionName), v->id, v->name); + plan = new EnumerateCollectionPlan(ast->query()->vocbase(), std::string(collectionName), v); + } + else if (expression->type == NODE_TYPE_REFERENCE) { + // second operand is already a variable + auto inVariable = static_cast(variable->getData()); + TRI_ASSERT(inVariable != nullptr); + plan = new EnumerateListPlan(inVariable, v); } else { - // generate a temporary variable - auto out = ast->variables()->createTemporaryVariable(); - - // generate a temporary calculation node - CalculationPlan* calc; - auto expr = new AqlExpression(expression); + // second operand is some misc. expression + auto calc = createTemporaryCalculation(ast, expression); try { - calc = new CalculationPlan(expr, out->id, out->name); - } - catch (...) { - // prevent memleak - delete expr; - throw; - } - - TRI_ASSERT(calc != nullptr); - - try { - plan = new EnumerateListPlan(out->id, out->name, v->id, v->name); + plan = new EnumerateListPlan(calc->outVariable(), v); plan->addDependency(calc); } catch (...) { @@ -169,10 +185,30 @@ ExecutionPlan* PlanGenerator::fromNodeFilter (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_FILTER); TRI_ASSERT(node->numMembers() == 1); - auto variable = node->getMember(0); - auto v = static_cast(variable->getData()); + auto expression = node->getMember(0); + + ExecutionPlan* plan = nullptr; - auto plan = new FilterPlan(v->id, v->name); + if (expression->type == NODE_TYPE_REFERENCE) { + // operand is already a variable + auto v = static_cast(expression->getData()); + TRI_ASSERT(v != nullptr); + plan = new FilterPlan(v); + } + else { + // operand is some misc expression + auto calc = createTemporaryCalculation(ast, expression); + + try { + plan = new FilterPlan(calc->outVariable()); + plan->addDependency(calc); + } + catch (...) { + // prevent memleak + delete calc; + } + } + return addDependency(previous, plan); } @@ -190,18 +226,28 @@ ExecutionPlan* PlanGenerator::fromNodeLet (Ast const* ast, AstNode const* expression = node->getMember(1); auto v = static_cast(variable->getData()); + + ExecutionPlan* plan = nullptr; - // TODO: node might be a subquery. this is currently NOT handled - auto expr = new AqlExpression(const_cast(expression)); - try { - auto plan = new CalculationPlan(expr, v->id, v->name); - return addDependency(previous, plan); + if (expression->type == NODE_TYPE_SUBQUERY) { + // TODO: node might be a subquery. this is currently NOT handled + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); } - catch (...) { - // prevent memleak - delete expr; - throw; + else { + // operand is some misc expression, including references to other variables + auto expr = new Expression(ast->query()->executor(), const_cast(expression)); + + try { + plan = new CalculationPlan(expr, v); + } + catch (...) { + // prevent memleak + delete expr; + throw; + } } + + return addDependency(previous, plan); } //////////////////////////////////////////////////////////////////////////////// @@ -214,10 +260,55 @@ ExecutionPlan* PlanGenerator::fromNodeSort (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_SORT); TRI_ASSERT(node->numMembers() == 1); - // TODO - THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + auto list = node->getMember(0); + TRI_ASSERT(list->type == NODE_TYPE_LIST); - return nullptr; + std::vector> elements; + std::vector temp; + + try { + size_t const n = list->numMembers(); + for (size_t i = 0; i < n; ++i) { + auto element = list->getMember(i); + TRI_ASSERT(element != nullptr); + TRI_ASSERT(element->type == NODE_TYPE_SORT_ELEMENT); + TRI_ASSERT(element->numMembers() == 1); + + auto expression = element->getMember(0); + + if (expression->type == NODE_TYPE_REFERENCE) { + // sort operand is a variable + auto v = static_cast(expression->getData()); + TRI_ASSERT(v != nullptr); + elements.push_back(std::make_pair(v, element->getBoolValue())); + } + else { + // sort operand is some misc expression + auto calc = createTemporaryCalculation(ast, expression); + temp.push_back(calc); + elements.push_back(std::make_pair(calc->outVariable(), element->getBoolValue())); + } + } + } + catch (...) { + // prevent memleak + for (auto it = temp.begin(); it != temp.end(); ++it) { + delete (*it); + } + throw; + } + + TRI_ASSERT(! elements.empty()); + + // properly link the temporary calculations in the plan + for (auto it = temp.begin(); it != temp.end(); ++it) { + (*it)->addDependency(previous); + previous = (*it); + } + + auto plan = new SortPlan(elements); + + return addDependency(previous, plan); } //////////////////////////////////////////////////////////////////////////////// @@ -269,11 +360,29 @@ ExecutionPlan* PlanGenerator::fromNodeReturn (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_RETURN); TRI_ASSERT(node->numMembers() == 1); - auto variable = node->getMember(0); - // TODO: the operand type of return is not necessarily a variable... - auto v = static_cast(variable->getData()); + auto expression = node->getMember(0); - auto plan = new RootPlan(v->id, v->name); + ExecutionPlan* plan = nullptr; + + if (expression->type == NODE_TYPE_REFERENCE) { + // operand is already a variable + auto v = static_cast(expression->getData()); + TRI_ASSERT(v != nullptr); + plan = new RootPlan(v); + } + else { + // operand is some misc expression + auto calc = createTemporaryCalculation(ast, expression); + + try { + plan = new RootPlan(calc->outVariable()); + plan->addDependency(calc); + } + catch (...) { + // prevent memleak + delete calc; + } + } return addDependency(previous, plan); } @@ -288,6 +397,8 @@ ExecutionPlan* PlanGenerator::fromNodeRemove (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REMOVE); // TODO + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + return nullptr; } @@ -301,6 +412,8 @@ ExecutionPlan* PlanGenerator::fromNodeInsert (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_INSERT); // TODO + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + return nullptr; } @@ -314,6 +427,8 @@ ExecutionPlan* PlanGenerator::fromNodeUpdate (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_UPDATE); // TODO + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + return nullptr; } @@ -327,6 +442,8 @@ ExecutionPlan* PlanGenerator::fromNodeReplace (Ast const* ast, TRI_ASSERT(node != nullptr && node->type == NODE_TYPE_REPLACE); // TODO + THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); + return nullptr; } @@ -340,84 +457,93 @@ ExecutionPlan* PlanGenerator::fromNode (Ast const* ast, ExecutionPlan* plan = new SingletonPlan(); - size_t const n = node->numMembers(); + try { + size_t const n = node->numMembers(); - for (size_t i = 0; i < n; ++i) { - auto member = node->getMember(i); - - if (member == nullptr || member->type == NODE_TYPE_NOP) { - continue; - } - - switch (member->type) { - case NODE_TYPE_FOR: { - plan = fromNodeFor(ast, plan, member); - break; + for (size_t i = 0; i < n; ++i) { + auto member = node->getMember(i); + + if (member == nullptr || member->type == NODE_TYPE_NOP) { + continue; } - case NODE_TYPE_FILTER: { - plan = fromNodeFilter(ast, plan, member); - break; + switch (member->type) { + case NODE_TYPE_FOR: { + plan = fromNodeFor(ast, plan, member); + break; + } + + case NODE_TYPE_FILTER: { + plan = fromNodeFilter(ast, plan, member); + break; + } + + case NODE_TYPE_LET: { + plan = fromNodeLet(ast, plan, member); + break; + } + + case NODE_TYPE_SORT: { + plan = fromNodeSort(ast, plan, member); + break; + } + + case NODE_TYPE_COLLECT: { + plan = fromNodeCollect(ast, plan, member); + break; + } + + case NODE_TYPE_LIMIT: { + plan = fromNodeLimit(ast, plan, member); + break; + } + + case NODE_TYPE_RETURN: { + plan = fromNodeReturn(ast, plan, member); + break; + } + + case NODE_TYPE_REMOVE: { + plan = fromNodeRemove(ast, plan, member); + break; + } + + case NODE_TYPE_INSERT: { + plan = fromNodeInsert(ast, plan, member); + break; + } + + case NODE_TYPE_UPDATE: { + plan = fromNodeUpdate(ast, plan, member); + break; + } + + case NODE_TYPE_REPLACE: { + plan = fromNodeReplace(ast, plan, member); + break; + } + + default: { + // node type not implemented + plan = nullptr; + break; + } } - case NODE_TYPE_LET: { - plan = fromNodeLet(ast, plan, member); - break; - } - - case NODE_TYPE_SORT: { - plan = fromNodeSort(ast, plan, member); - break; - } - - case NODE_TYPE_COLLECT: { - plan = fromNodeCollect(ast, plan, member); - break; - } - - case NODE_TYPE_LIMIT: { - plan = fromNodeLimit(ast, plan, member); - break; - } - - case NODE_TYPE_RETURN: { - plan = fromNodeReturn(ast, plan, member); - break; - } - - case NODE_TYPE_REMOVE: { - plan = fromNodeRemove(ast, plan, member); - break; - } - - case NODE_TYPE_INSERT: { - plan = fromNodeInsert(ast, plan, member); - break; - } - - case NODE_TYPE_UPDATE: { - plan = fromNodeUpdate(ast, plan, member); - break; - } - - case NODE_TYPE_REPLACE: { - plan = fromNodeReplace(ast, plan, member); - break; - } - - default: { - // node type not implemented - plan = nullptr; - break; + if (plan == nullptr) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } } - - if (plan == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); - } + + return plan; + } + catch (...) { + // prevent memleak + if (plan != nullptr) { + delete plan; + } + throw; } - - return plan; } // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/PlanGenerator.h b/arangod/Aql/PlanGenerator.h index 8f6976bcfe..453b595811 100644 --- a/arangod/Aql/PlanGenerator.h +++ b/arangod/Aql/PlanGenerator.h @@ -37,6 +37,7 @@ namespace triagens { class Ast; struct AstNode; + class CalculationPlan; class ExecutionPlan; // ----------------------------------------------------------------------------- @@ -81,6 +82,13 @@ namespace triagens { private: +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a calculation node for an arbitrary expression +//////////////////////////////////////////////////////////////////////////////// + + CalculationPlan* createTemporaryCalculation (Ast const*, + AstNode const*); + //////////////////////////////////////////////////////////////////////////////// /// @brief adds "previous" as dependency to "plan", returns "plan" //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index cd22666c97..f8fc2f83f3 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -28,7 +28,9 @@ //////////////////////////////////////////////////////////////////////////////// #include "Aql/Query.h" +#include "Aql/ExecutionBlock.h" #include "Aql/Parser.h" +#include "Aql/PlanGenerator.h" #include "Aql/V8Executor.h" #include "BasicsC/json.h" #include "BasicsC/tri-strings.h" @@ -163,23 +165,63 @@ void Query::registerError (int code, /// @brief execute an AQL query - TODO: implement and determine return type //////////////////////////////////////////////////////////////////////////////// -ParseResult Query::execute () { +QueryResult Query::execute () { try { Parser parser(this); parser.parse(); parser.ast()->injectBindParameters(_bindParameters); parser.ast()->optimize(); - - ParseResult result(TRI_ERROR_NO_ERROR); - result.json = parser.ast()->toJson(TRI_UNKNOWN_MEM_ZONE); + PlanGenerator generator; + auto plan = generator.fromAst(parser.ast()); + + try { + auto exec = ExecutionBlock::instanciatePlan(plan); + + try { + exec->staticAnalysis(); + + exec->initialize(); + exec->execute(); + + shared_ptr value; + while (nullptr != (value = exec->getOne())) { + std::cout << value->getValue(0, 0)->toString() << std::endl; + value.reset(); + } + + exec->shutdown(); + delete exec; + } + catch (...) { + delete exec; + delete plan; + // TODO: convert exception code + return QueryResult(TRI_ERROR_INTERNAL); + } + } + catch (triagens::arango::Exception const& ex) { + delete plan; + return QueryResult(ex.code(), ex.message()); + } + catch (...) { + delete plan; + // TODO: convert exception code + return QueryResult(TRI_ERROR_INTERNAL); + } + + delete plan; + + QueryResult result(TRI_ERROR_NO_ERROR); + // result.json = parser.ast()->toJson(TRI_UNKNOWN_MEM_ZONE); + return result; } catch (triagens::arango::Exception const& ex) { - return ParseResult(ex.code(), ex.message()); + return QueryResult(ex.code(), ex.message()); } catch (...) { - return ParseResult(TRI_ERROR_OUT_OF_MEMORY, TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY)); + return QueryResult(TRI_ERROR_OUT_OF_MEMORY, TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY)); } } @@ -187,16 +229,16 @@ ParseResult Query::execute () { /// @brief parse an AQL query //////////////////////////////////////////////////////////////////////////////// -ParseResult Query::parse () { +QueryResult Query::parse () { try { Parser parser(this); return parser.parse(); } catch (triagens::arango::Exception const& ex) { - return ParseResult(ex.code(), ex.message()); + return QueryResult(ex.code(), ex.message()); } catch (...) { - return ParseResult(TRI_ERROR_OUT_OF_MEMORY, TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY)); + return QueryResult(TRI_ERROR_OUT_OF_MEMORY, TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY)); } } diff --git a/arangod/Aql/Query.h b/arangod/Aql/Query.h index bead769528..2a08908e8b 100644 --- a/arangod/Aql/Query.h +++ b/arangod/Aql/Query.h @@ -32,7 +32,7 @@ #include "Basics/Common.h" #include "Aql/BindParameters.h" -#include "Aql/ParseResult.h" +#include "Aql/QueryResult.h" struct TRI_json_s; struct TRI_vocbase_s; @@ -95,6 +95,14 @@ namespace triagens { return _vocbase; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the V8 executor +//////////////////////////////////////////////////////////////////////////////// + + inline V8Executor* executor () { + return _executor; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief get the query type //////////////////////////////////////////////////////////////////////////////// @@ -142,16 +150,16 @@ namespace triagens { char const* = nullptr); //////////////////////////////////////////////////////////////////////////////// -/// @brief execute an AQL query - TODO: implement and determine return type +/// @brief execute an AQL query //////////////////////////////////////////////////////////////////////////////// - ParseResult execute (); + QueryResult execute (); //////////////////////////////////////////////////////////////////////////////// /// @brief parse an AQL query //////////////////////////////////////////////////////////////////////////////// - ParseResult parse (); + QueryResult parse (); //////////////////////////////////////////////////////////////////////////////// /// @brief explain an AQL query - TODO: implement and determine return type diff --git a/arangod/Aql/ParseResult.h b/arangod/Aql/QueryResult.h similarity index 88% rename from arangod/Aql/ParseResult.h rename to arangod/Aql/QueryResult.h index 74e7054dbe..f722d1a3bf 100644 --- a/arangod/Aql/ParseResult.h +++ b/arangod/Aql/QueryResult.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -/// @brief Aql, parse results +/// @brief Aql, query results /// /// @file /// @@ -27,8 +27,8 @@ /// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#ifndef ARANGODB_AQL_PARSE_RESULT_H -#define ARANGODB_AQL_PARSE_RESULT_H 1 +#ifndef ARANGODB_AQL_QUERY_RESULT_H +#define ARANGODB_AQL_QUERY_RESULT_H 1 #include "Basics/Common.h" #include "BasicsC/json.h" @@ -37,13 +37,13 @@ namespace triagens { namespace aql { // ----------------------------------------------------------------------------- -// --SECTION-- struct ParseResult +// --SECTION-- struct QueryResult // ----------------------------------------------------------------------------- - struct ParseResult { - ParseResult& operator= (ParseResult const& other) = delete; + struct QueryResult { + QueryResult& operator= (QueryResult const& other) = delete; - ParseResult (ParseResult&& other) { + QueryResult (QueryResult&& other) { code = other.code; details = other.details; json = other.json; @@ -51,7 +51,7 @@ namespace triagens { other.json = nullptr; } - ParseResult (int code, + QueryResult (int code, std::string const& details) : code(code), details(details), @@ -59,21 +59,21 @@ namespace triagens { json(nullptr) { } - explicit ParseResult (int code) + explicit QueryResult (int code) : code(code), details(""), zone(TRI_UNKNOWN_MEM_ZONE), json(nullptr) { } - ParseResult () + QueryResult () : code(TRI_ERROR_NO_ERROR), details(), zone(TRI_UNKNOWN_MEM_ZONE), json(nullptr) { } - ~ParseResult () { + ~QueryResult () { if (json != nullptr) { TRI_FreeJson(zone, json); } diff --git a/arangod/Aql/Variable.cpp b/arangod/Aql/Variable.cpp new file mode 100644 index 0000000000..55f886ca53 --- /dev/null +++ b/arangod/Aql/Variable.cpp @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Aql, AST variable +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "Aql/Variable.h" + +using namespace triagens::aql; +using Json = triagens::basics::Json; + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the variable +//////////////////////////////////////////////////////////////////////////////// + +Variable::Variable (std::string const& name, + VariableId id) + : name(name), + value(nullptr), + id(id), + refCount(0) { +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the variable +//////////////////////////////////////////////////////////////////////////////// + +Variable::~Variable () { +} + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a JSON representation of the variable +//////////////////////////////////////////////////////////////////////////////// + +Json Variable::toJson () const { + Json json(triagens::basics::Json::Array, 2); + json("id", Json(static_cast(id))) + ("name", Json(name)); + + return json; +} + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" +// End: diff --git a/arangod/Aql/Variable.h b/arangod/Aql/Variable.h index 3714a9104d..5517a7b384 100644 --- a/arangod/Aql/Variable.h +++ b/arangod/Aql/Variable.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -/// @brief Aql, AST variables +/// @brief Aql, AST variable /// /// @file /// @@ -31,6 +31,7 @@ #define ARANGODB_AQL_VARIABLE_H 1 #include "Basics/Common.h" +#include "Basics/JsonHelper.h" namespace triagens { namespace aql { @@ -42,18 +43,23 @@ namespace triagens { // ----------------------------------------------------------------------------- struct Variable { - Variable (std::string const& name, - VariableId id, - bool isUserDefined) - : name(name), - value(nullptr), - id(id), - refCount(0), - isUserDefined(isUserDefined) { - } - ~Variable () { - } +//////////////////////////////////////////////////////////////////////////////// +/// @brief create the variable +//////////////////////////////////////////////////////////////////////////////// + + Variable (std::string const&, + VariableId); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy the variable +//////////////////////////////////////////////////////////////////////////////// + + ~Variable (); + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief registers a constant value for the variable @@ -97,15 +103,49 @@ namespace triagens { --refCount; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the variable is user-defined +//////////////////////////////////////////////////////////////////////////////// + + inline bool isUserDefined () const { + char const c = name[0]; + // variables starting with a number are user-defined + return (c >= '0' && c <= '9'); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a JSON representation of the variable +//////////////////////////////////////////////////////////////////////////////// + + triagens::basics::Json toJson () const; + // ----------------------------------------------------------------------------- // --SECTION-- public variables // ----------------------------------------------------------------------------- - std::string const name; - void* value; - VariableId const id; - uint32_t refCount; - bool const isUserDefined; +//////////////////////////////////////////////////////////////////////////////// +/// @brief variable name +//////////////////////////////////////////////////////////////////////////////// + + std::string const name; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constant variable value (points to another AstNode) +//////////////////////////////////////////////////////////////////////////////// + + void* value; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief variable id +//////////////////////////////////////////////////////////////////////////////// + + VariableId const id; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief number of times the variable is used in the AST +//////////////////////////////////////////////////////////////////////////////// + + uint32_t refCount; }; diff --git a/arangod/Aql/VariableGenerator.cpp b/arangod/Aql/VariableGenerator.cpp index cec23a11e4..2401f39bc2 100644 --- a/arangod/Aql/VariableGenerator.cpp +++ b/arangod/Aql/VariableGenerator.cpp @@ -65,7 +65,11 @@ VariableGenerator::~VariableGenerator () { Variable* VariableGenerator::createVariable (char const* name, bool isUserDefined) { - auto variable = new Variable(std::string(name), nextId(), isUserDefined); + auto variable = new Variable(std::string(name), nextId()); + + if (isUserDefined) { + TRI_ASSERT(variable->isUserDefined()); + } try { _variables.insert(std::make_pair(variable->id, variable)); @@ -85,7 +89,11 @@ Variable* VariableGenerator::createVariable (char const* name, Variable* VariableGenerator::createVariable (std::string const& name, bool isUserDefined) { - auto variable = new Variable(name, nextId(), isUserDefined); + auto variable = new Variable(name, nextId()); + + if (isUserDefined) { + TRI_ASSERT(variable->isUserDefined()); + } try { _variables.insert(std::make_pair(variable->id, variable)); @@ -126,6 +134,8 @@ Variable* VariableGenerator::getVariable (VariableId id) const { //////////////////////////////////////////////////////////////////////////////// std::string VariableGenerator::nextName () const { + // note: if the naming scheme is adjusted, it may be necessary to adjust + // Variable::isUserDefined, too! return std::to_string(_id); // to_string: c++11 } diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index d9a03fedf2..18b9f86c55 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -62,6 +62,7 @@ add_executable( Aql/BindParameters.cpp Aql/ExecutionBlock.cpp Aql/ExecutionPlan.cpp + Aql/Expression.cpp Aql/grammar.cpp Aql/Parser.cpp Aql/PlanGenerator.cpp @@ -70,6 +71,7 @@ add_executable( Aql/Types.cpp Aql/tokens.cpp Aql/V8Executor.cpp + Aql/Variable.cpp Aql/VariableGenerator.cpp BitIndexes/bitarray.cpp BitIndexes/bitarrayIndex.cpp diff --git a/arangod/Cluster/v8-cluster.cpp b/arangod/Cluster/v8-cluster.cpp index 33d0438953..963f5ac73a 100644 --- a/arangod/Cluster/v8-cluster.cpp +++ b/arangod/Cluster/v8-cluster.cpp @@ -1515,9 +1515,12 @@ static v8::Handle JS_AsyncRequest (v8::Arguments const& argv) { // - coordTransactionID (number) // - timeout (number) - if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { - TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); - } + // Disabled to allow communication originating in a DBserver: + // 31.7.2014 Max + + // if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { + // TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); + //} ClusterComm* cc = ClusterComm::instance(); @@ -1572,9 +1575,12 @@ static v8::Handle JS_SyncRequest (v8::Arguments const& argv) { // - coordTransactionID (number) // - timeout (number) - if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { - TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); - } + // Disabled to allow communication originating in a DBserver: + // 31.7.2014 Max + + //if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { + // TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); + //} ClusterComm* cc = ClusterComm::instance(); @@ -1626,9 +1632,12 @@ static v8::Handle JS_Enquire (v8::Arguments const& argv) { TRI_V8_EXCEPTION_USAGE(scope, "enquire(operationID)"); } - if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { - TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); - } + // Disabled to allow communication originating in a DBserver: + // 31.7.2014 Max + + // if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { + // TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); + // } ClusterComm* cc = ClusterComm::instance(); @@ -1668,9 +1677,12 @@ static v8::Handle JS_Wait (v8::Arguments const& argv) { // - shardID (string) // - timeout (number) - if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { - TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); - } + // Disabled to allow communication originating in a DBserver: + // 31.7.2014 Max + + // if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { + // TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); + // } ClusterComm* cc = ClusterComm::instance(); @@ -1742,9 +1754,12 @@ static v8::Handle JS_Drop (v8::Arguments const& argv) { // - operationID (number) // - shardID (string) - if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { - TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); - } + // Disabled to allow communication originating in a DBserver: + // 31.7.2014 Max + + // if (ServerState::instance()->getRole() != ServerState::ROLE_COORDINATOR) { + // TRI_V8_EXCEPTION_INTERNAL(scope,"request works only in coordinator role"); + // } ClusterComm* cc = ClusterComm::instance(); diff --git a/arangod/Makefile.files b/arangod/Makefile.files index 3a4b83af48..1bfbcf9372 100644 --- a/arangod/Makefile.files +++ b/arangod/Makefile.files @@ -43,6 +43,7 @@ arangod_libarangod_a_SOURCES = \ arangod/Aql/BindParameters.cpp \ arangod/Aql/ExecutionBlock.cpp \ arangod/Aql/ExecutionPlan.cpp \ + arangod/Aql/Expression.cpp \ arangod/Aql/grammar.cpp \ arangod/Aql/Parser.cpp \ arangod/Aql/PlanGenerator.cpp \ @@ -51,6 +52,7 @@ arangod_libarangod_a_SOURCES = \ arangod/Aql/Types.cpp \ arangod/Aql/tokens.cpp \ arangod/Aql/V8Executor.cpp \ + arangod/Aql/Variable.cpp \ arangod/Aql/VariableGenerator.cpp \ arangod/BitIndexes/bitarray.cpp \ arangod/BitIndexes/bitarrayIndex.cpp \ diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index cef46f03db..7fa5539142 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -5397,71 +5397,6 @@ static v8::Handle JS_ParseAql (v8::Arguments const& argv) { return scope.Close(result); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief peng an AQL query -//////////////////////////////////////////////////////////////////////////////// - -class MyWorker : public triagens::aql::ExecutionBlock::WalkerWorker { - public: - int count; - MyWorker () : count(0) {}; - ~MyWorker () {}; - void before (triagens::aql::ExecutionBlock* eb) { - std::cout << "Before node of type " << eb->getPlan()->getTypeString() - << std::endl; - count++; - } - void after (triagens::aql::ExecutionBlock* eb) { - std::cout << "After node of type " << eb->getPlan()->getTypeString() - << std::endl; - } -}; - -static v8::Handle JS_PengAql (v8::Arguments const& argv) { - v8::HandleScope scope; - - TRI_vocbase_t* vocbase = GetContextVocBase(); - - if (vocbase == nullptr) { - TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); - } - - if (argv.Length() != 0) { - TRI_V8_EXCEPTION_USAGE(scope, "AQL_PENG()"); - } - - triagens::aql::ExecutionPlan* singlePlan = new triagens::aql::SingletonPlan(); - triagens::aql::ExecutionPlan* enumPlan = new triagens::aql::EnumerateCollectionPlan(vocbase, "fuxx", 1, "f"); - enumPlan->addDependency(singlePlan); - triagens::aql::ExecutionPlan* rootPlan = new triagens::aql::RootPlan(1,"X"); - rootPlan->addDependency(enumPlan); - - triagens::aql::ExecutionBlock* exec = triagens::aql::ExecutionBlock::instanciatePlan (rootPlan); - - exec->staticAnalysis(); - - MyWorker w; - exec->walk(w); - std::cout << "Count is " << w.count << std::endl; - - exec->initialize(); - exec->execute(); - - shared_ptr value; - while (nullptr != (value = exec->getOne())) { - std::cout << "Peng" << std::endl; - std::cout << value->getValue(0,0)->toString() << std::endl; - value.reset(); - } - - exec->shutdown(); - - delete exec; - delete rootPlan; - - return scope.Close(v8::Undefined()); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief executes an AQL query //////////////////////////////////////////////////////////////////////////////// @@ -5499,14 +5434,16 @@ static v8::Handle JS_ExecuteAql (v8::Arguments const& argv) { // bind parameters will be freed by the query later triagens::aql::Query query(vocbase, queryString.c_str(), queryString.size(), parameters); - auto parseResult = query.execute(); - - if (parseResult.code != TRI_ERROR_NO_ERROR) { - TRI_V8_EXCEPTION_FULL(scope, parseResult.code, parseResult.details); + auto queryResult = query.execute(); + + if (queryResult.code != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION_FULL(scope, queryResult.code, queryResult.details); } v8::Handle result = v8::Object::New(); - result->Set(TRI_V8_STRING("ast"), TRI_ObjectJson(parseResult.json)); + if (queryResult.json != nullptr) { + result->Set(TRI_V8_STRING("json"), TRI_ObjectJson(queryResult.json)); + } return scope.Close(result); } @@ -10778,7 +10715,6 @@ void TRI_InitV8VocBridge (v8::Handle context, // new AQL functions. not intended to be used directly by end users TRI_AddGlobalFunctionVocbase(context, "AQL_EXECUTE", JS_ExecuteAql, true); TRI_AddGlobalFunctionVocbase(context, "AQL_PARSE", JS_ParseAql, true); - TRI_AddGlobalFunctionVocbase(context, "AQL_PENG", JS_PengAql, true); // cursor functions. not intended to be used by end users TRI_AddGlobalFunctionVocbase(context, "CURSOR", JS_Cursor, true);