1
0
Fork 0

issue #271: allow very simple optimisations for AQL function usage

This change will create field access hints also for AQL function calls.
Calls to functions will not be optimised, but meaningless usages of functions will not be optimised away.
For example:

FOR p IN PATHS(users, relations, "outbound")
  FILTER LENGTH(p.edges) > 0 && LENGTH(p.edges) < 0
  RETURN p

The FILTER in the above query uses the LENGTH() function two times in a way that no result will be produced.
Before, function calls were excluded from expression collapsing and simplification.
Now, multiple calls to the same function with the same call argument might be optimised away if the calls will
lead to no results being produced. This will only work for functions that are called with exactly one argument
which also must be an attribute name, and when the function calls are used in relational operations.
This commit is contained in:
Jan Steemann 2012-10-26 13:22:48 +02:00
parent 792f57b760
commit a68fff16e2
3 changed files with 58 additions and 21 deletions

View File

@ -27,6 +27,8 @@
#include "Ahuacatl/ahuacatl-access-optimiser.h"
#include "Ahuacatl/ahuacatl-functions.h"
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
@ -1784,7 +1786,7 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con
assert(field);
assert(field->_name._buffer);
assert(node);
fieldAccess = (TRI_aql_field_access_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_field_access_t), false);
if (fieldAccess == NULL) {
// OOM
@ -1807,8 +1809,8 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con
fieldAccess->_type = TRI_AQL_ACCESS_ALL;
return fieldAccess;
}
}
if (node->_type == TRI_AQL_NODE_REFERENCE ||
node->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS) {
// create the reference access
@ -1908,13 +1910,13 @@ static TRI_aql_field_access_t* GetAttributeAccess (TRI_aql_context_t* const cont
assert(context);
assert(node);
if (!field || !field->_name._buffer) {
if (field == NULL || ! field->_name._buffer) {
// this is ok if the node type is not supported
return NULL;
}
fieldAccess = CreateAccessForNode(context, field, operator, node);
if (!fieldAccess) {
if (fieldAccess == NULL) {
// OOM
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
return NULL;
@ -1962,6 +1964,29 @@ static TRI_aql_attribute_name_t* GetAttributeName (TRI_aql_context_t* const cont
return field;
}
else if (node->_type == TRI_AQL_NODE_FCALL) {
TRI_aql_function_t* function = (TRI_aql_function_t*) TRI_AQL_NODE_DATA(node);
TRI_aql_node_t* args = TRI_AQL_NODE_MEMBER(node, 0);
TRI_aql_attribute_name_t* field;
// if we have anything but 1 function call argument, we cannot optimise this
if (args->_members._length != 1) {
return NULL;
}
field = GetAttributeName(context, TRI_AQL_NODE_MEMBER(args, 0));
if (field == NULL) {
return NULL;
}
// name of generated attribute is XXX.FUNC(), e.g. for LENGTH(users.friends) => users.friends.LENGTH()
TRI_AppendCharStringBuffer(&field->_name, '.');
TRI_AppendStringStringBuffer(&field->_name, function->_externalName);
TRI_AppendStringStringBuffer(&field->_name, "()");
return field;
}
return NULL;
}
@ -2046,28 +2071,28 @@ static TRI_vector_pointer_t* ProcessNode (TRI_aql_context_t* const context,
useBoth = false;
if ((lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS) &&
(TRI_IsConstantValueNodeAql(rhs) || rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS)) {
// collection.attribute|reference operator const value|reference|attribute access
if ((lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || lhs->_type == TRI_AQL_NODE_FCALL) &&
(TRI_IsConstantValueNodeAql(rhs) || rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || rhs->_type == TRI_AQL_NODE_FCALL)) {
// collection.attribute|reference|fcall operator const value|reference|attribute access|fcall
node1 = lhs;
node2 = rhs;
operator = node->_type;
if (rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS) {
// expression of type reference|attribute access operator reference|attribute access
if (rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || rhs->_type == TRI_AQL_NODE_FCALL) {
// expression of type reference|attribute access|fcall operator reference|attribute access|fcall
useBoth = true;
}
}
else if ((rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS) &&
(TRI_IsConstantValueNodeAql(lhs) || lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS)) {
// const value|reference|attribute access operator collection.attribute|reference
else if ((rhs->_type == TRI_AQL_NODE_REFERENCE || rhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || rhs->_type == TRI_AQL_NODE_FCALL) &&
(TRI_IsConstantValueNodeAql(lhs) || lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || lhs->_type == TRI_AQL_NODE_FCALL)) {
// const value|reference|attribute|fcall access operator collection.attribute|reference|fcall
node1 = rhs;
node2 = lhs;
operator = TRI_ReverseOperatorRelationalAql(node->_type);
assert(operator != TRI_AQL_NODE_NOP);
if (lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS) {
// expression of type reference|attribute access operator reference|attribute access
if (lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || lhs->_type == TRI_AQL_NODE_FCALL) {
// expression of type reference|attribute access|fcall operator reference|attribute access|fcall
useBoth = true;
}
}
@ -2090,7 +2115,7 @@ again:
// we'll get back here for expressions of type a.x == b.y (where both sides are references)
field = GetAttributeName(context, node1);
if (field) {
if (field && node2->_type != TRI_AQL_NODE_FCALL) {
TRI_aql_field_access_t* attributeAccess = GetAttributeAccess(context, field, operator, node2);
TRI_vector_pointer_t* result;

View File

@ -59,7 +59,7 @@
#define CREATE_NODE(type) \
TRI_aql_node_t* node = (TRI_aql_node_t*) \
TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_t), false); \
if (!node) { \
if (node == NULL) { \
ABORT_OOM \
} \
\
@ -71,7 +71,7 @@
////////////////////////////////////////////////////////////////////////////////
#define ADD_MEMBER(member) \
if (!member) { \
if (member == NULL) { \
ABORT_OOM \
} \
\

View File

@ -312,6 +312,15 @@ static bool EqualName (TRI_associative_pointer_t* array,
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- optimiser callbacks
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief optimise callback function for PATHS() AQL function
////////////////////////////////////////////////////////////////////////////////
@ -336,8 +345,6 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
return;
}
assert(args->_members._length >= 3);
vertexCollection = TRI_AQL_NODE_MEMBER(args, 0);
edgeCollection = TRI_AQL_NODE_MEMBER(args, 1);
direction = TRI_AQL_NODE_MEMBER(args, 2);
@ -352,6 +359,7 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
directionValue = TRI_AQL_NODE_STRING(direction);
// try to optimise the vertex collection access
if (TRI_EqualString(directionValue, "outbound")) {
lookFor = ".source.";
len = strlen(lookFor);
@ -375,12 +383,16 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
// copy trailing \0 byte as well
memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2);
// attach the modified fieldAccess to the collection
// attach the modified fieldaccess to the collection
hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------