1
0
Fork 0

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

This commit is contained in:
Max Neunhoeffer 2014-07-29 15:13:36 +02:00
commit a35f066477
7 changed files with 270 additions and 61 deletions

View File

@ -76,8 +76,7 @@ void AstNode::toJson (TRI_json_t* json,
// dump node type
TRI_Insert3ArrayJson(zone, node, "type", TRI_CreateStringCopyJson(zone, typeString().c_str()));
if (type == NODE_TYPE_REFERENCE ||
type == NODE_TYPE_COLLECTION ||
if (type == NODE_TYPE_COLLECTION ||
type == NODE_TYPE_PARAMETER ||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
type == NODE_TYPE_FCALL ||
@ -109,7 +108,8 @@ void AstNode::toJson (TRI_json_t* json,
}
}
if (type == NODE_TYPE_VARIABLE) {
if (type == NODE_TYPE_VARIABLE ||
type == NODE_TYPE_REFERENCE) {
auto variable = static_cast<Variable*>(getData());
TRI_Insert3ArrayJson(zone, node, "name", TRI_CreateStringCopyJson(zone, variable->name.c_str()));
@ -301,8 +301,6 @@ std::string AstNode::typeString () const {
return "user function call";
case NODE_TYPE_RANGE:
return "range";
case NODE_TYPE_NOP:
return "no-op";
default: {
}
}

View File

@ -123,8 +123,7 @@ namespace triagens {
NODE_TYPE_PARAMETER,
NODE_TYPE_FCALL,
NODE_TYPE_FCALL_USER,
NODE_TYPE_RANGE,
NODE_TYPE_NOP,
NODE_TYPE_RANGE
};
// -----------------------------------------------------------------------------
@ -270,7 +269,15 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the int value of a node
/// @brief return the int value of a node, without asserting the node type
////////////////////////////////////////////////////////////////////////////////
inline int64_t getIntValue (bool) const {
return value.value._int;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the int value of a node, with asserting the node type
////////////////////////////////////////////////////////////////////////////////
inline int64_t getIntValue () const {

View File

@ -65,8 +65,7 @@ QueryAst::QueryAst (Query* query,
_collectionNames(),
_root(nullptr),
_writeCollection(nullptr),
_writeOptions(nullptr),
_nopNode() {
_writeOptions(nullptr) {
TRI_ASSERT(_query != nullptr);
TRI_ASSERT(_parser != nullptr);
@ -200,6 +199,7 @@ AstNode* QueryAst::createNodeLet (char const* variableName,
AstNode* QueryAst::createNodeFilter (AstNode const* expression) {
AstNode* node = createNode(NODE_TYPE_FILTER);
node->setIntValue(static_cast<int64_t>(FILTER_UNKNOWN));
node->addMember(expression);
return node;
@ -403,7 +403,14 @@ AstNode* QueryAst::createNodeCollection (char const* name) {
AstNode* QueryAst::createNodeReference (char const* name) {
AstNode* node = createNode(NODE_TYPE_REFERENCE);
node->setStringValue(name);
auto variable = _scopes.getVariable(name);
if (variable == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
}
node->setData(variable);
return node;
}
@ -666,20 +673,6 @@ AstNode* QueryAst::createNodeRange (AstNode const* start,
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a no-op node
/// note: the same no-op node can be returned multiple times
////////////////////////////////////////////////////////////////////////////////
AstNode* QueryAst::createNodeNop () {
// the nop node is a singleton inside a query
if (_nopNode == nullptr) {
_nopNode = createNode(NODE_TYPE_NOP);
}
return _nopNode;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief injects bind parameters into the AST
////////////////////////////////////////////////////////////////////////////////
@ -793,11 +786,28 @@ void QueryAst::optimize () {
if (node->type == NODE_TYPE_OPERATOR_TERNARY) {
return optimizeTernaryOperator(node);
}
// reference to a variable
if (node->type == NODE_TYPE_REFERENCE) {
return optimizeReference(node);
}
// range
if (node->type == NODE_TYPE_RANGE) {
return optimizeRange(node);
}
// LET
if (node->type == NODE_TYPE_LET) {
return optimizeLet(node);
}
return node;
};
_root = traverse(_root, func, nullptr);
optimizeRoot();
}
// -----------------------------------------------------------------------------
@ -853,12 +863,16 @@ AstNode* QueryAst::optimizeFilter (AstNode* node) {
return node;
}
if (operand->getBoolValue()) {
// FILTER is always true, optimize it away
return createNodeNop();
}
TRI_ASSERT(node->getIntValue(true) == static_cast<int64_t>(FILTER_UNKNOWN));
// TODO: optimize FILTERs that are always false
if (operand->getBoolValue()) {
// FILTER is always true
node->setIntValue(static_cast<int64_t>(FILTER_TRUE));
}
else {
// FILTER is always false
node->setIntValue(static_cast<int64_t>(FILTER_FALSE));
}
return node;
}
@ -1164,6 +1178,130 @@ AstNode* QueryAst::optimizeTernaryOperator (AstNode* node) {
return falsePart;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes a reference to a variable
////////////////////////////////////////////////////////////////////////////////
AstNode* QueryAst::optimizeReference (AstNode* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->type == NODE_TYPE_REFERENCE);
auto variable = static_cast<Variable*>(node->getData());
if (variable == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
if (variable->constValue() == nullptr) {
return node;
}
return static_cast<AstNode*>(variable->constValue());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the range operator
////////////////////////////////////////////////////////////////////////////////
AstNode* QueryAst::optimizeRange (AstNode* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->type == NODE_TYPE_RANGE);
TRI_ASSERT(node->numMembers() == 2);
AstNode* lhs = node->getMember(0);
AstNode* rhs = node->getMember(1);
if (lhs == nullptr || rhs == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
if (! lhs->isConstant() || ! rhs->isConstant()) {
return node;
}
if (! lhs->isNumericValue() || ! rhs->isNumericValue()) {
_parser->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
return node;
}
double const l = lhs->getDoubleValue();
double const r = rhs->getDoubleValue();
if (l < r) {
return node;
}
// x..y with x > y, replace with empty list
return createNodeList();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the LET statement
////////////////////////////////////////////////////////////////////////////////
AstNode* QueryAst::optimizeLet (AstNode* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->type == NODE_TYPE_LET);
TRI_ASSERT(node->numMembers() == 2);
AstNode* variable = node->getMember(0);
AstNode* expression = node->getMember(1);
if (expression->isConstant()) {
// if the expression assigned to the LET variable is constant, we'll store
// a pointer to the const value in the variable
// further optimizations can then use this pointer and optimize further, e.g.
// LET a = 1 LET b = a + 1, c = b + a can be optimized to LET a = 1 LET b = 2 LET c = 4
auto v = static_cast<Variable*>(variable->getData());
TRI_ASSERT(v != nullptr);
v->constValue(static_cast<void*>(expression));
}
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the top-level statements
////////////////////////////////////////////////////////////////////////////////
void QueryAst::optimizeRoot() {
TRI_ASSERT(_root != nullptr);
TRI_ASSERT(_root->type == NODE_TYPE_ROOT);
size_t const n = _root->numMembers();
for (size_t i = 0; i < n; ++i) {
AstNode* member = _root->getMember(i);
if (member == nullptr) {
continue;
}
if (member->type == NODE_TYPE_FOR) {
// peek forward and check if the for contains a FILTER that is always false
bool isEmpty = false;
for (size_t j = i + 1; j < n; ++j) {
AstNode* sub = _root->getMember(j);
if (sub == nullptr) {
continue;
}
if (sub->type == NODE_TYPE_FILTER) {
// TODO: found a FILTER that is always false
isEmpty = true;
}
if (sub->type == NODE_TYPE_RETURN) {
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST node from JSON
////////////////////////////////////////////////////////////////////////////////

View File

@ -56,6 +56,12 @@ namespace triagens {
class QueryAst {
enum FilterType {
FILTER_UNKNOWN,
FILTER_TRUE,
FILTER_FALSE
};
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
@ -81,8 +87,6 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return a copy of our own bind parameters
////////////////////////////////////////////////////////////////////////////////
@ -387,13 +391,6 @@ namespace triagens {
AstNode* createNodeRange (AstNode const*,
AstNode const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief create a no-op node
/// note: the same no-op node can be returned multiple times
////////////////////////////////////////////////////////////////////////////////
AstNode* createNodeNop ();
////////////////////////////////////////////////////////////////////////////////
/// @brief injects bind parameters into the AST
////////////////////////////////////////////////////////////////////////////////
@ -464,6 +461,30 @@ namespace triagens {
AstNode* optimizeTernaryOperator (AstNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes a reference to a variable
////////////////////////////////////////////////////////////////////////////////
AstNode* optimizeReference (AstNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the range operator
////////////////////////////////////////////////////////////////////////////////
AstNode* optimizeRange (AstNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the LET statement
////////////////////////////////////////////////////////////////////////////////
AstNode* optimizeLet (AstNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief optimizes the top-level statements
////////////////////////////////////////////////////////////////////////////////
void optimizeRoot ();
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST node from JSON
////////////////////////////////////////////////////////////////////////////////
@ -556,12 +577,6 @@ namespace triagens {
AstNode const* _writeOptions;
////////////////////////////////////////////////////////////////////////////////
/// @brief a reusable no-operation node
////////////////////////////////////////////////////////////////////////////////
AstNode* _nopNode;
////////////////////////////////////////////////////////////////////////////////
/// @brief AQL function names
////////////////////////////////////////////////////////////////////////////////

View File

@ -99,19 +99,28 @@ Variable* Scope::addVariable (std::string const& name,
return variable;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief end a scope
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if a variable exists in the scope
////////////////////////////////////////////////////////////////////////////////
bool Scope::existsVariable (char const* name) const {
TRI_ASSERT(name != nullptr);
auto it = _variables.find(std::string(name));
return (getVariable(name) != nullptr);
}
return (it != _variables.end());
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a variable
////////////////////////////////////////////////////////////////////////////////
Variable* Scope::getVariable (char const* name) const {
std::string const varname(name);
auto it = _variables.find(varname);
if (it == _variables.end()) {
return nullptr;
}
return (*it).second;
}
// -----------------------------------------------------------------------------
@ -203,6 +212,7 @@ void Scopes::endNested () {
Variable* Scopes::addVariable (char const* name,
bool isUserDefined) {
TRI_ASSERT(! _activeScopes.empty());
TRI_ASSERT(name != nullptr);
for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) {
auto scope = (*it);
@ -223,17 +233,25 @@ Variable* Scopes::addVariable (char const* name,
////////////////////////////////////////////////////////////////////////////////
bool Scopes::existsVariable (char const* name) const {
return (getVariable(name) != nullptr);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a variable
////////////////////////////////////////////////////////////////////////////////
Variable* Scopes::getVariable (char const* name) const {
TRI_ASSERT(! _activeScopes.empty());
for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) {
auto scope = (*it);
auto variable = (*it)->getVariable(name);
if (scope->existsVariable(name)) {
return true;
if (variable != nullptr) {
return variable;
}
}
return false;
return nullptr;
}
// -----------------------------------------------------------------------------

View File

@ -44,6 +44,7 @@ namespace triagens {
size_t id,
bool isUserDefined)
: name(name),
value(nullptr),
id(id),
isUserDefined(isUserDefined) {
}
@ -51,7 +52,29 @@ namespace triagens {
~Variable () {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief registers a constant value for the variable
/// this constant value is used for constant propagation in optimizations
////////////////////////////////////////////////////////////////////////////////
void constValue (void* node) {
value = node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a constant value registered for this variable
////////////////////////////////////////////////////////////////////////////////
void* constValue () const {
return value;
}
// -----------------------------------------------------------------------------
// --SECTION-- public variables
// -----------------------------------------------------------------------------
std::string const name;
void* value;
size_t const id;
bool const isUserDefined;
};
@ -125,6 +148,12 @@ namespace triagens {
bool existsVariable (char const*) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return a variable
////////////////////////////////////////////////////////////////////////////////
Variable* getVariable (char const*) const;
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
@ -209,6 +238,12 @@ namespace triagens {
bool existsVariable (char const*) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return a variable
////////////////////////////////////////////////////////////////////////////////
Variable* getVariable (char const*) const;
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------

View File

@ -443,11 +443,7 @@ expression:
auto subQuery = parser->ast()->createNodeSubquery(tempName);
parser->ast()->addOperation(subQuery);
auto nameNode = subQuery->getMember(0);
auto result = parser->ast()->createNodeReference(nameNode->getStringValue());
// return the result
$$ = result;
$$ = parser->ast()->createNodeReference(tempName);
}
| operator_unary {
$$ = $1;
@ -683,6 +679,7 @@ reference:
parser->pushStack($1);
// create a temporary variable for the row iterator (will be popped by "expansion" rule")
// TODO:
auto node = parser->ast()->createNodeReference(varname);
// push the variable
@ -700,6 +697,7 @@ reference:
auto nameNode = expand->getMember(1);
// return a reference only
// TODO:
$$ = parser->ast()->createNodeReference(nameNode->getStringValue());
}
;