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 // dump node type
TRI_Insert3ArrayJson(zone, node, "type", TRI_CreateStringCopyJson(zone, typeString().c_str())); TRI_Insert3ArrayJson(zone, node, "type", TRI_CreateStringCopyJson(zone, typeString().c_str()));
if (type == NODE_TYPE_REFERENCE || if (type == NODE_TYPE_COLLECTION ||
type == NODE_TYPE_COLLECTION ||
type == NODE_TYPE_PARAMETER || type == NODE_TYPE_PARAMETER ||
type == NODE_TYPE_ATTRIBUTE_ACCESS || type == NODE_TYPE_ATTRIBUTE_ACCESS ||
type == NODE_TYPE_FCALL || 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()); auto variable = static_cast<Variable*>(getData());
TRI_Insert3ArrayJson(zone, node, "name", TRI_CreateStringCopyJson(zone, variable->name.c_str())); 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"; return "user function call";
case NODE_TYPE_RANGE: case NODE_TYPE_RANGE:
return "range"; return "range";
case NODE_TYPE_NOP:
return "no-op";
default: { default: {
} }
} }

View File

@ -123,8 +123,7 @@ namespace triagens {
NODE_TYPE_PARAMETER, NODE_TYPE_PARAMETER,
NODE_TYPE_FCALL, NODE_TYPE_FCALL,
NODE_TYPE_FCALL_USER, NODE_TYPE_FCALL_USER,
NODE_TYPE_RANGE, NODE_TYPE_RANGE
NODE_TYPE_NOP,
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -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 { inline int64_t getIntValue () const {

View File

@ -65,8 +65,7 @@ QueryAst::QueryAst (Query* query,
_collectionNames(), _collectionNames(),
_root(nullptr), _root(nullptr),
_writeCollection(nullptr), _writeCollection(nullptr),
_writeOptions(nullptr), _writeOptions(nullptr) {
_nopNode() {
TRI_ASSERT(_query != nullptr); TRI_ASSERT(_query != nullptr);
TRI_ASSERT(_parser != nullptr); TRI_ASSERT(_parser != nullptr);
@ -200,6 +199,7 @@ AstNode* QueryAst::createNodeLet (char const* variableName,
AstNode* QueryAst::createNodeFilter (AstNode const* expression) { AstNode* QueryAst::createNodeFilter (AstNode const* expression) {
AstNode* node = createNode(NODE_TYPE_FILTER); AstNode* node = createNode(NODE_TYPE_FILTER);
node->setIntValue(static_cast<int64_t>(FILTER_UNKNOWN));
node->addMember(expression); node->addMember(expression);
return node; return node;
@ -403,7 +403,14 @@ AstNode* QueryAst::createNodeCollection (char const* name) {
AstNode* QueryAst::createNodeReference (char const* name) { AstNode* QueryAst::createNodeReference (char const* name) {
AstNode* node = createNode(NODE_TYPE_REFERENCE); 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; return node;
} }
@ -666,20 +673,6 @@ AstNode* QueryAst::createNodeRange (AstNode const* start,
return node; 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 /// @brief injects bind parameters into the AST
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -794,10 +787,27 @@ void QueryAst::optimize () {
return optimizeTernaryOperator(node); 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; return node;
}; };
_root = traverse(_root, func, nullptr); _root = traverse(_root, func, nullptr);
optimizeRoot();
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -853,12 +863,16 @@ AstNode* QueryAst::optimizeFilter (AstNode* node) {
return node; return node;
} }
if (operand->getBoolValue()) { TRI_ASSERT(node->getIntValue(true) == static_cast<int64_t>(FILTER_UNKNOWN));
// FILTER is always true, optimize it away
return createNodeNop();
}
// 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; return node;
} }
@ -1164,6 +1178,130 @@ AstNode* QueryAst::optimizeTernaryOperator (AstNode* node) {
return falsePart; 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 /// @brief create an AST node from JSON
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -56,6 +56,12 @@ namespace triagens {
class QueryAst { class QueryAst {
enum FilterType {
FILTER_UNKNOWN,
FILTER_TRUE,
FILTER_FALSE
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors // --SECTION-- constructors / destructors
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -81,8 +87,6 @@ namespace triagens {
public: public:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief return a copy of our own bind parameters /// @brief return a copy of our own bind parameters
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -387,13 +391,6 @@ namespace triagens {
AstNode* createNodeRange (AstNode const*, AstNode* createNodeRange (AstNode const*,
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 /// @brief injects bind parameters into the AST
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -464,6 +461,30 @@ namespace triagens {
AstNode* optimizeTernaryOperator (AstNode*); 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 /// @brief create an AST node from JSON
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -556,12 +577,6 @@ namespace triagens {
AstNode const* _writeOptions; AstNode const* _writeOptions;
////////////////////////////////////////////////////////////////////////////////
/// @brief a reusable no-operation node
////////////////////////////////////////////////////////////////////////////////
AstNode* _nopNode;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief AQL function names /// @brief AQL function names
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -44,6 +44,7 @@ namespace triagens {
size_t id, size_t id,
bool isUserDefined) bool isUserDefined)
: name(name), : name(name),
value(nullptr),
id(id), id(id),
isUserDefined(isUserDefined) { isUserDefined(isUserDefined) {
} }
@ -51,7 +52,29 @@ namespace triagens {
~Variable () { ~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; std::string const name;
void* value;
size_t const id; size_t const id;
bool const isUserDefined; bool const isUserDefined;
}; };
@ -125,6 +148,12 @@ namespace triagens {
bool existsVariable (char const*) const; bool existsVariable (char const*) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return a variable
////////////////////////////////////////////////////////////////////////////////
Variable* getVariable (char const*) const;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --SECTION-- private variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -209,6 +238,12 @@ namespace triagens {
bool existsVariable (char const*) const; bool existsVariable (char const*) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return a variable
////////////////////////////////////////////////////////////////////////////////
Variable* getVariable (char const*) const;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --SECTION-- private variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

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