1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
Max Neunhoeffer 2014-07-31 16:07:34 +02:00
commit b7a2add68c
21 changed files with 855 additions and 690 deletions

View File

@ -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);

View File

@ -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

View File

@ -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<ExecutionPlan*> deps = ep->getDependencies();
@ -117,26 +117,26 @@ int ExecutionBlock::staticAnalysisRecursion (
_depth++;
curVar = 0;
auto p = static_cast<EnumerateCollectionPlan const*>(_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<EnumerateListPlan const*>(_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<CalculationPlan const*>(_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<ProjectionPlan const*>(_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

View File

@ -177,15 +177,9 @@ void EnumerateCollectionPlan::toJsonHelper (std::map<ExecutionPlan*, int>& index
}
// Now put info about vocbase and cid in there
if (_vocbase == nullptr) {
json("vocbase", Json("<nullptr>"));
}
else {
json("vocbase", Json(_vocbase->_name));
}
json("collection", Json(_collname))
("outVarNumber", Json(static_cast<double>(_outVarNumber)))
("outVarName", Json(_outVarName));
json("database", Json(_vocbase->_name))
("collection", Json(_collname))
("outVariable", _outVariable->toJson());
// And add it:
int len = static_cast<int>(nodes.size());
@ -208,11 +202,8 @@ void EnumerateListPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
json("varNumber", Json(static_cast<double>(_varNumber)))
("varName", Json(_varName))
("outVarNumber", Json(static_cast<double>(_outVarNumber)))
("outVarName", Json(_outVarName));
json("inVariable", _inVariable->toJson())
("outVariable", _outVariable->toJson());
// And add it:
int len = static_cast<int>(nodes.size());
@ -260,9 +251,9 @@ void CalculationPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
json("varNumber", Json(static_cast<double>(_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<int>(nodes.size());
@ -285,9 +276,8 @@ void SubqueryPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
json("varNumber", Json(static_cast<double>(_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<int>(nodes.size());
@ -314,10 +304,9 @@ void ProjectionPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
for (auto it = _keepAttributes.begin(); it != _keepAttributes.end(); ++it) {
vec(Json(*it));
}
json("inVarNumber", Json(static_cast<double>(_inVar)))
("inVarName", Json(_inVarName))
("outVarNumber", Json(static_cast<double>(_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<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
// Now put info about offset and limit in
json("varName", Json(_varName))
("varNumber", Json(static_cast<double>(_varNumber)));
json("inVariable", _inVariable->toJson());
// And add it:
int len = static_cast<int>(nodes.size());
@ -366,21 +354,14 @@ void SortPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
Json numbers(Json::List, _varNumbers.size());
for (auto it = _varNumbers.begin(); it != _varNumbers.end(); ++it) {
numbers(Json(static_cast<double>(*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<int>(nodes.size());
@ -403,18 +384,20 @@ void AggregateOnUnsortedPlan::toJsonHelper (std::map<ExecutionPlan*, int>& index
if (json.isEmpty()) {
return;
}
Json numbers(Json::List, _varNumbers.size());
for (auto it = _varNumbers.begin(); it != _varNumbers.end(); ++it) {
numbers(Json(static_cast<double>(*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<double>(_outVarNumber)))
("outVarName", Json(_outVarName));
// And add it:
int len = static_cast<int>(nodes.size());
@ -437,8 +420,8 @@ void RootPlan::toJsonHelper (std::map<ExecutionPlan*, int>& indexTab,
if (json.isEmpty()) {
return;
}
json("varNumber", Json(static_cast<double>(_varNumber)))
("varName" , Json(_varName));
json("inVariable", _inVariable->toJson());
// And add it:
int len = static_cast<int>(nodes.size());
@ -446,246 +429,6 @@ void RootPlan::toJsonHelper (std::map<ExecutionPlan*, int>& 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<VariableId> vars;
std::vector<std::string> names;
std::vector<bool> 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--\\|/// @\\}\\)"

View File

@ -34,6 +34,7 @@
#include <VocBase/voc-types.h>
#include <VocBase/vocbase.h>
#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<ExecutionPlan*>(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<ExecutionPlan*>(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<std::string> 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<ExecutionPlan*>(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<ExecutionPlan*>(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<ExecutionPlan*>(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<ExecutionPlan*>(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<VariableId> varNumbers,
std::vector<std::string> varNames,
std::vector<bool> sortAscending)
: ExecutionPlan(), _varNumbers(varNumbers), _varNames(varNames),
_sortAscending(sortAscending) {
SortPlan (std::vector<std::pair<Variable const*, bool>> 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<ExecutionPlan*>(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<VariableId> _varNumbers;
////////////////////////////////////////////////////////////////////////////////
/// @brief _varNames, name of variables for sorting
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> _varNames;
////////////////////////////////////////////////////////////////////////////////
/// @brief vector of attributes to sort by
////////////////////////////////////////////////////////////////////////////////
std::vector<bool> _sortAscending;
std::vector<std::pair<Variable const*, bool>> _elements;
};
@ -1047,12 +999,9 @@ namespace triagens {
public:
AggregateOnUnsortedPlan (std::vector<VariableId> varNumbers,
std::vector<std::string> varNames,
VariableId outVarNumber,
std::string outVarName)
: ExecutionPlan(), _varNumbers(varNumbers), _varNames(varNames),
_outVarNumber(outVarNumber), _outVarName(outVarName) {
AggregateOnUnsortedPlan (std::vector<std::pair<Variable const*, Variable const*>> 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<ExecutionPlan*>(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<VariableId> _varNumbers;
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;
////////////////////////////////////////////////////////////////////////////////
/// @brief _varNames, name of variables for the aggregation
/// @brief output variable to write to (might be null)
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> _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<ExecutionPlan*>(c);
}
@ -1186,9 +1124,7 @@ namespace triagens {
private:
VariableId _varNumber;
std::string _varName;
Variable const* _inVariable;
};
} // namespace triagens::aql

View File

@ -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:

133
arangod/Aql/Expression.h Normal file
View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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<AstNode*>(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*>(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*>(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<Variable*>(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*>(variable->getData());
ExecutionPlan* plan = nullptr;
// TODO: node might be a subquery. this is currently NOT handled
auto expr = new AqlExpression(const_cast<AstNode*>(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<AstNode*>(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<std::pair<Variable const*, bool>> elements;
std::vector<CalculationPlan*> 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<Variable*>(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*>(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<Variable*>(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;
}
// -----------------------------------------------------------------------------

View File

@ -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"
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<AqlItem> 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));
}
}

View File

@ -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

View File

@ -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);
}

81
arangod/Aql/Variable.cpp Normal file
View File

@ -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<double>(id)))
("name", Json(name));
return json;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -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;
};

View File

@ -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
}

View File

@ -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

View File

@ -1515,9 +1515,12 @@ static v8::Handle<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Value> 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<v8::Value> 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();

View File

@ -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 \

View File

@ -5397,71 +5397,6 @@ static v8::Handle<v8::Value> 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<v8::Value> 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<triagens::aql::AqlItem> 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<v8::Value> 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<v8::Object> 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<v8::Context> 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);