mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
a35f066477
|
@ -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: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -793,11 +786,28 @@ void QueryAst::optimize () {
|
||||||
if (node->type == NODE_TYPE_OPERATOR_TERNARY) {
|
if (node->type == NODE_TYPE_OPERATOR_TERNARY) {
|
||||||
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
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue