mirror of https://gitee.com/bigwinds/arangodb
refactored range optimizer
This commit is contained in:
parent
4174b215f7
commit
926a158a99
|
@ -37,41 +37,29 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief hash a field name
|
/// @brief create a vector with an attribute access struct in it
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static uint64_t HashFieldAccess (TRI_associative_pointer_t* array,
|
static TRI_vector_pointer_t* Vectorize (TRI_aql_context_t* const context,
|
||||||
void const* element) {
|
TRI_aql_field_access_t* fieldAccess) {
|
||||||
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) element;
|
TRI_vector_pointer_t* vector;
|
||||||
|
|
||||||
return TRI_FnvHashString(fieldAccess->_fieldName);
|
assert(context);
|
||||||
}
|
if (!fieldAccess) {
|
||||||
|
return NULL;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief comparison function used to determine field name equality
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static bool EqualFieldAccess (TRI_associative_pointer_t* array,
|
|
||||||
void const* key,
|
|
||||||
void const* element) {
|
|
||||||
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) element;
|
|
||||||
|
|
||||||
return TRI_EqualString(key, fieldAccess->_fieldName);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief return the logical type for a sub operation
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static inline TRI_aql_logical_e SubOperator (const TRI_aql_logical_e preferredType,
|
|
||||||
const TRI_aql_logical_e parentType) {
|
|
||||||
if (parentType == TRI_AQL_LOGICAL_NOT) {
|
|
||||||
// logical NOT is sticky
|
|
||||||
return parentType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// all other operators are not
|
vector = (TRI_vector_pointer_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_vector_pointer_t), false);
|
||||||
return preferredType;
|
if (!vector) {
|
||||||
|
// OOM
|
||||||
|
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_InitVectorPointer(vector, TRI_UNKNOWN_MEM_ZONE);
|
||||||
|
TRI_PushBackVectorPointer(vector, fieldAccess);
|
||||||
|
|
||||||
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -146,25 +134,7 @@ static void FreeAccess (TRI_aql_context_t* const context,
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, fieldAccess);
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, fieldAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief merge two access structures using a logical NOT
|
|
||||||
///
|
|
||||||
/// this always returns the all items range because we cannot evaluate the
|
|
||||||
/// negated condition
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static TRI_aql_field_access_t* MergeNot (TRI_aql_context_t* const context,
|
|
||||||
TRI_aql_field_access_t* lhs,
|
|
||||||
TRI_aql_field_access_t* rhs) {
|
|
||||||
// always returns all
|
|
||||||
FreeAccess(context, rhs);
|
|
||||||
FreeAccessMembers(lhs);
|
|
||||||
|
|
||||||
lhs->_type = TRI_AQL_ACCESS_ALL;
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief merge two access structures using a logical AND
|
/// @brief merge two access structures using a logical AND
|
||||||
///
|
///
|
||||||
|
@ -1105,28 +1075,20 @@ static TRI_aql_field_access_t* MergeOrRangeDouble (TRI_aql_context_t* const cont
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief merge two access structures using either logical AND or OR
|
/// @brief free access structure with its members and the pointer
|
||||||
|
///
|
||||||
|
/// TODO: fix docs
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static TRI_aql_field_access_t* MergeAccess (TRI_aql_context_t* const context,
|
static TRI_aql_field_access_t* MergeAttributeAccessAnd (TRI_aql_context_t* const context,
|
||||||
const TRI_aql_logical_e logicalType,
|
TRI_aql_field_access_t* lhs,
|
||||||
TRI_aql_field_access_t* lhs,
|
TRI_aql_field_access_t* rhs) {
|
||||||
TRI_aql_field_access_t* rhs) {
|
assert(context);
|
||||||
assert(context);
|
assert(lhs);
|
||||||
assert(lhs);
|
assert(rhs);
|
||||||
assert(rhs);
|
|
||||||
assert(logicalType == TRI_AQL_LOGICAL_AND ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_OR ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_NOT);
|
|
||||||
|
|
||||||
assert(lhs->_fieldName != NULL);
|
assert(lhs->_fieldName != NULL);
|
||||||
assert(rhs->_fieldName != NULL);
|
assert(rhs->_fieldName != NULL);
|
||||||
|
|
||||||
if (logicalType == TRI_AQL_LOGICAL_NOT) {
|
|
||||||
// logical NOT is simple. we simply turn everything into an all range
|
|
||||||
return MergeNot(context, lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lhs->_type > rhs->_type) {
|
if (lhs->_type > rhs->_type) {
|
||||||
// swap operands so they are always sorted
|
// swap operands so they are always sorted
|
||||||
TRI_aql_field_access_t* tmp = lhs;
|
TRI_aql_field_access_t* tmp = lhs;
|
||||||
|
@ -1136,45 +1098,176 @@ static TRI_aql_field_access_t* MergeAccess (TRI_aql_context_t* const context,
|
||||||
|
|
||||||
assert(lhs->_type <= rhs->_type);
|
assert(lhs->_type <= rhs->_type);
|
||||||
|
|
||||||
if (logicalType == TRI_AQL_LOGICAL_AND) {
|
switch (lhs->_type) {
|
||||||
// logical AND
|
case TRI_AQL_ACCESS_IMPOSSIBLE:
|
||||||
switch (lhs->_type) {
|
return MergeAndImpossible(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_IMPOSSIBLE:
|
case TRI_AQL_ACCESS_ALL:
|
||||||
return MergeAndImpossible(context, lhs, rhs);
|
return MergeAndAll(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_ALL:
|
case TRI_AQL_ACCESS_EXACT:
|
||||||
return MergeAndAll(context, lhs, rhs);
|
return MergeAndExact(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_EXACT:
|
case TRI_AQL_ACCESS_LIST:
|
||||||
return MergeAndExact(context, lhs, rhs);
|
return MergeAndList(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_LIST:
|
case TRI_AQL_ACCESS_RANGE_SINGLE:
|
||||||
return MergeAndList(context, lhs, rhs);
|
return MergeAndRangeSingle(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_RANGE_SINGLE:
|
case TRI_AQL_ACCESS_RANGE_DOUBLE:
|
||||||
return MergeAndRangeSingle(context, lhs, rhs);
|
return MergeAndRangeDouble(context, lhs, rhs);
|
||||||
case TRI_AQL_ACCESS_RANGE_DOUBLE:
|
|
||||||
return MergeAndRangeDouble(context, lhs, rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// logical OR
|
|
||||||
switch (lhs->_type) {
|
|
||||||
case TRI_AQL_ACCESS_IMPOSSIBLE:
|
|
||||||
return MergeOrImpossible(context, lhs, rhs);
|
|
||||||
case TRI_AQL_ACCESS_ALL:
|
|
||||||
return MergeOrAll(context, lhs, rhs);
|
|
||||||
case TRI_AQL_ACCESS_EXACT:
|
|
||||||
return MergeOrExact(context, lhs, rhs);
|
|
||||||
case TRI_AQL_ACCESS_LIST:
|
|
||||||
return MergeOrList(context, lhs, rhs);
|
|
||||||
case TRI_AQL_ACCESS_RANGE_SINGLE:
|
|
||||||
return MergeOrRangeSingle(context, lhs, rhs);
|
|
||||||
case TRI_AQL_ACCESS_RANGE_DOUBLE:
|
|
||||||
return MergeOrRangeDouble(context, lhs, rhs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief free access structure with its members and the pointer
|
||||||
|
///
|
||||||
|
/// TODO: fix docs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_aql_field_access_t* MergeAttributeAccessOr (TRI_aql_context_t* const context,
|
||||||
|
TRI_aql_field_access_t* lhs,
|
||||||
|
TRI_aql_field_access_t* rhs) {
|
||||||
|
assert(context);
|
||||||
|
assert(lhs);
|
||||||
|
assert(rhs);
|
||||||
|
assert(lhs->_fieldName != NULL);
|
||||||
|
assert(rhs->_fieldName != NULL);
|
||||||
|
|
||||||
|
if (lhs->_type > rhs->_type) {
|
||||||
|
// swap operands so they are always sorted
|
||||||
|
TRI_aql_field_access_t* tmp = lhs;
|
||||||
|
lhs = rhs;
|
||||||
|
rhs = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(lhs->_type <= rhs->_type);
|
||||||
|
|
||||||
|
switch (lhs->_type) {
|
||||||
|
case TRI_AQL_ACCESS_IMPOSSIBLE:
|
||||||
|
return MergeOrImpossible(context, lhs, rhs);
|
||||||
|
case TRI_AQL_ACCESS_ALL:
|
||||||
|
return MergeOrAll(context, lhs, rhs);
|
||||||
|
case TRI_AQL_ACCESS_EXACT:
|
||||||
|
return MergeOrExact(context, lhs, rhs);
|
||||||
|
case TRI_AQL_ACCESS_LIST:
|
||||||
|
return MergeOrList(context, lhs, rhs);
|
||||||
|
case TRI_AQL_ACCESS_RANGE_SINGLE:
|
||||||
|
return MergeOrRangeSingle(context, lhs, rhs);
|
||||||
|
case TRI_AQL_ACCESS_RANGE_DOUBLE:
|
||||||
|
return MergeOrRangeDouble(context, lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief process a logical NOT
|
||||||
|
///
|
||||||
|
/// TODO: fix docs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_vector_pointer_t* MakeAllVector (TRI_aql_context_t* const context,
|
||||||
|
TRI_vector_pointer_t* const fieldAccesses) {
|
||||||
|
size_t i, n;
|
||||||
|
|
||||||
|
if (!fieldAccesses) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = fieldAccesses->_length;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
// turn all field access values into an all items access
|
||||||
|
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(fieldAccesses, i);
|
||||||
|
|
||||||
|
// modify the element in place
|
||||||
|
FreeAccessMembers(fieldAccess);
|
||||||
|
fieldAccess->_type = TRI_AQL_ACCESS_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldAccesses;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief process a logical OR
|
||||||
|
///
|
||||||
|
/// TODO: fix docs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static TRI_vector_pointer_t* MergeVectors (TRI_aql_context_t* const context,
|
||||||
|
const TRI_aql_logical_e logicalType,
|
||||||
|
TRI_vector_pointer_t* const lhs,
|
||||||
|
TRI_vector_pointer_t* const rhs) {
|
||||||
|
TRI_vector_pointer_t* result;
|
||||||
|
size_t i, n;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
assert(logicalType == TRI_AQL_LOGICAL_AND || logicalType == TRI_AQL_LOGICAL_OR);
|
||||||
|
|
||||||
|
// if one of the vectors is empty, simply return the other one
|
||||||
|
if (!lhs) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rhs) {
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// both vectors are non empty
|
||||||
|
|
||||||
|
result = (TRI_vector_pointer_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_vector_pointer_t), false);
|
||||||
|
if (!result) {
|
||||||
|
// OOM
|
||||||
|
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_InitVectorPointer(result, TRI_UNKNOWN_MEM_ZONE);
|
||||||
|
|
||||||
|
// copy elements from lhs into result vector
|
||||||
|
n = lhs->_length;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(lhs, i);
|
||||||
|
TRI_PushBackVectorPointer(result, fieldAccess);
|
||||||
|
}
|
||||||
|
// can now free lhs vector
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, lhs);
|
||||||
|
|
||||||
|
// copy elements from rhs into result vector
|
||||||
|
n = rhs->_length;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(rhs, i);
|
||||||
|
size_t j, len;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// check if element is in result vector already
|
||||||
|
len = result->_length;
|
||||||
|
for (j = 0; j < len; ++j) {
|
||||||
|
TRI_aql_field_access_t* compareAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(result, j);
|
||||||
|
|
||||||
|
if (TRI_EqualString(fieldAccess->_fieldName, compareAccess->_fieldName)) {
|
||||||
|
// found the element
|
||||||
|
if (logicalType == TRI_AQL_LOGICAL_AND) {
|
||||||
|
result->_buffer[i] = MergeAttributeAccessAnd(context, fieldAccess, compareAccess);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result->_buffer[i] = MergeAttributeAccessOr(context, fieldAccess, compareAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
TRI_PushBackVectorPointer(result, fieldAccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// can now free rhs vector
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, rhs);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an access structure for the given node and operator
|
/// @brief create an access structure for the given node and operator
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1216,6 +1309,10 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con
|
||||||
fieldAccess->_type = TRI_AQL_ACCESS_EXACT;
|
fieldAccess->_type = TRI_AQL_ACCESS_EXACT;
|
||||||
fieldAccess->_value._value = value;
|
fieldAccess->_value._value = value;
|
||||||
}
|
}
|
||||||
|
else if (operator == AQL_NODE_OPERATOR_BINARY_NE) {
|
||||||
|
// create an all items access
|
||||||
|
fieldAccess->_type = TRI_AQL_ACCESS_ALL;
|
||||||
|
}
|
||||||
else if (operator == AQL_NODE_OPERATOR_BINARY_LT) {
|
else if (operator == AQL_NODE_OPERATOR_BINARY_LT) {
|
||||||
// create a single range access
|
// create a single range access
|
||||||
fieldAccess->_type = TRI_AQL_ACCESS_RANGE_SINGLE;
|
fieldAccess->_type = TRI_AQL_ACCESS_RANGE_SINGLE;
|
||||||
|
@ -1264,57 +1361,32 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create an access structure for the given node and operator,
|
/// @brief create an access structure for the given node and operator,
|
||||||
/// merge it with potential others already found for the same variable
|
/// merge it with potential others already found for the same variable
|
||||||
|
///
|
||||||
|
/// TODO fix docs
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void NoteAttributeAccess (TRI_aql_context_t* const context,
|
static TRI_aql_field_access_t* GetAttributeAccess (TRI_aql_context_t* const context,
|
||||||
const TRI_aql_logical_e logicalType,
|
const TRI_aql_attribute_name_t* const field,
|
||||||
const TRI_aql_attribute_name_t* const field,
|
const TRI_aql_node_type_e operator,
|
||||||
const TRI_aql_node_type_e operator,
|
const TRI_aql_node_t* const node) {
|
||||||
const TRI_aql_node_t* const node) {
|
|
||||||
TRI_aql_field_access_t* previous;
|
|
||||||
TRI_aql_field_access_t* fieldAccess;
|
TRI_aql_field_access_t* fieldAccess;
|
||||||
|
|
||||||
assert(context);
|
assert(context);
|
||||||
assert(logicalType == TRI_AQL_LOGICAL_AND ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_OR ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_NOT);
|
|
||||||
assert(node);
|
assert(node);
|
||||||
|
|
||||||
if (!field || !field->_name._buffer) {
|
if (!field || !field->_name._buffer) {
|
||||||
return;
|
// this is ok if the node type is not supported
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldAccess = CreateAccessForNode(context, field, operator, node);
|
fieldAccess = CreateAccessForNode(context, field, operator, node);
|
||||||
if (!fieldAccess) {
|
if (!fieldAccess) {
|
||||||
// OOM
|
// OOM
|
||||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// look up previous range first
|
return fieldAccess;
|
||||||
previous = (TRI_aql_field_access_t*) TRI_LookupByKeyAssociativePointer(context->_ranges, fieldAccess->_fieldName);
|
|
||||||
if (previous) {
|
|
||||||
TRI_aql_field_access_t* merged;
|
|
||||||
// previous range exists, now merge new access type with previous one
|
|
||||||
|
|
||||||
// remove from hash first
|
|
||||||
TRI_RemoveKeyAssociativePointer(context->_ranges, fieldAccess->_fieldName);
|
|
||||||
|
|
||||||
// MergeAccess() will free previous and/or fieldAccess
|
|
||||||
merged = MergeAccess(context, logicalType, fieldAccess, previous);
|
|
||||||
|
|
||||||
if (!merged) {
|
|
||||||
// OOM
|
|
||||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_InsertKeyAssociativePointer(context->_ranges, merged->_fieldName, merged, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// no previous access exists, no need to merge
|
|
||||||
TRI_InsertKeyAssociativePointer(context->_ranges, fieldAccess->_fieldName, fieldAccess, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1360,67 +1432,85 @@ static TRI_aql_attribute_name_t* GetAttributeName (TRI_aql_context_t* const cont
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @}
|
/// @brief inspect a condition node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
static TRI_vector_pointer_t* ProcessNode (TRI_aql_context_t* const context,
|
||||||
// --SECTION-- constructors / destructors
|
TRI_aql_node_t* node) {
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @addtogroup Ahuacatl
|
|
||||||
/// @{
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief init the optimizer
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool TRI_InitOptimizerAql (TRI_aql_context_t* const context) {
|
|
||||||
assert(context);
|
assert(context);
|
||||||
assert(context->_ranges == NULL);
|
assert(node);
|
||||||
|
|
||||||
context->_ranges = (TRI_associative_pointer_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_associative_pointer_t), false);
|
if (node->_type == AQL_NODE_OPERATOR_UNARY_NOT) {
|
||||||
if (!context->_ranges) {
|
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
|
||||||
return false;
|
assert(lhs);
|
||||||
|
|
||||||
|
return MakeAllVector(context, ProcessNode(context, lhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_InitAssociativePointer(context->_ranges,
|
if (node->_type == AQL_NODE_OPERATOR_BINARY_OR) {
|
||||||
TRI_UNKNOWN_MEM_ZONE,
|
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
&TRI_HashStringKeyAssociativePointer,
|
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
||||||
&HashFieldAccess,
|
|
||||||
&EqualFieldAccess,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
return true;
|
assert(lhs);
|
||||||
}
|
assert(rhs);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// recurse into next level
|
||||||
/// @brief shutdown the optimizer
|
return MergeVectors(context,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
TRI_AQL_LOGICAL_OR,
|
||||||
|
ProcessNode(context, lhs),
|
||||||
|
ProcessNode(context, rhs));
|
||||||
|
}
|
||||||
|
|
||||||
void TRI_FreeOptimizerAql (TRI_aql_context_t* const context) {
|
if (node->_type == AQL_NODE_OPERATOR_BINARY_AND) {
|
||||||
assert(context);
|
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
|
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
||||||
|
|
||||||
|
assert(lhs);
|
||||||
|
assert(rhs);
|
||||||
|
|
||||||
if (context->_ranges) {
|
// recurse into next level
|
||||||
size_t i, n;
|
return MergeVectors(context,
|
||||||
|
TRI_AQL_LOGICAL_AND,
|
||||||
|
ProcessNode(context, lhs),
|
||||||
|
ProcessNode(context, rhs));
|
||||||
|
}
|
||||||
|
|
||||||
// free all remaining access elements
|
if (node->_type == AQL_NODE_OPERATOR_BINARY_EQ ||
|
||||||
n = context->_ranges->_nrAlloc;
|
node->_type == AQL_NODE_OPERATOR_BINARY_NE ||
|
||||||
for (i = 0; i < n; ++i) {
|
node->_type == AQL_NODE_OPERATOR_BINARY_LT ||
|
||||||
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) context->_ranges->_table[i];
|
node->_type == AQL_NODE_OPERATOR_BINARY_LE ||
|
||||||
if (!fieldAccess) {
|
node->_type == AQL_NODE_OPERATOR_BINARY_GT ||
|
||||||
continue;
|
node->_type == AQL_NODE_OPERATOR_BINARY_GE ||
|
||||||
|
node->_type == AQL_NODE_OPERATOR_BINARY_IN) {
|
||||||
|
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
||||||
|
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
||||||
|
|
||||||
|
if (lhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) {
|
||||||
|
TRI_aql_attribute_name_t* field = GetAttributeName(context, lhs);
|
||||||
|
|
||||||
|
if (field) {
|
||||||
|
TRI_aql_field_access_t* attributeAccess = GetAttributeAccess(context, field, node->_type, rhs);
|
||||||
|
TRI_DestroyStringBuffer(&field->_name);
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, field);
|
||||||
|
|
||||||
|
return Vectorize(context, attributeAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeAccess(context, fieldAccess);
|
|
||||||
}
|
}
|
||||||
|
else if (rhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) {
|
||||||
|
TRI_aql_attribute_name_t* field = GetAttributeName(context, rhs);
|
||||||
|
|
||||||
// free hash array
|
if (field) {
|
||||||
TRI_FreeAssociativePointer(TRI_UNKNOWN_MEM_ZONE, context->_ranges);
|
TRI_aql_field_access_t* attributeAccess = GetAttributeAccess(context, field, node->_type, lhs);
|
||||||
context->_ranges = NULL;
|
TRI_DestroyStringBuffer(&field->_name);
|
||||||
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, field);
|
||||||
|
|
||||||
|
return Vectorize(context, attributeAccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1440,17 +1530,14 @@ void TRI_FreeOptimizerAql (TRI_aql_context_t* const context) {
|
||||||
/// @brief dump ranges found for debugging purposes
|
/// @brief dump ranges found for debugging purposes
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_DumpRangesAql (TRI_aql_context_t* const context) {
|
void TRI_DumpRangesAql (const TRI_vector_pointer_t* const ranges) {
|
||||||
size_t i;
|
size_t i, n;
|
||||||
|
|
||||||
assert(context);
|
assert(ranges);
|
||||||
|
|
||||||
for (i = 0; i < context->_ranges->_nrAlloc; ++i) {
|
n = ranges->_length;
|
||||||
TRI_aql_field_access_t* fieldAccess = context->_ranges->_table[i];
|
for (i = 0; i < n; ++i) {
|
||||||
|
TRI_aql_field_access_t* fieldAccess = TRI_AtVectorPointer(ranges, i);
|
||||||
if (!fieldAccess) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nFIELD ACCESS\n- FIELD: %s\n",fieldAccess->_fieldName);
|
printf("\nFIELD ACCESS\n- FIELD: %s\n",fieldAccess->_fieldName);
|
||||||
printf("- TYPE: %s\n", AccessName(fieldAccess->_type));
|
printf("- TYPE: %s\n", AccessName(fieldAccess->_type));
|
||||||
|
@ -1482,89 +1569,17 @@ void TRI_DumpRangesAql (TRI_aql_context_t* const context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief inspect a condition and note all accesses found for it
|
/// @brief inspect a condition and note all accesses found for it
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_InspectConditionAql (TRI_aql_context_t* const context,
|
TRI_vector_pointer_t* TRI_InspectConditionAql (TRI_aql_context_t* const context,
|
||||||
const TRI_aql_logical_e logicalType,
|
TRI_aql_node_t* node,
|
||||||
TRI_aql_node_t* node) {
|
const TRI_vector_pointer_t* const parentRestrictions) {
|
||||||
assert(context);
|
return ProcessNode(context, node);
|
||||||
assert(logicalType == TRI_AQL_LOGICAL_AND ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_OR ||
|
|
||||||
logicalType == TRI_AQL_LOGICAL_NOT);
|
|
||||||
|
|
||||||
if (node->_type == AQL_NODE_OPERATOR_UNARY_NOT) {
|
|
||||||
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
|
||||||
|
|
||||||
assert(lhs);
|
|
||||||
|
|
||||||
TRI_InspectConditionAql(context, TRI_AQL_LOGICAL_NOT, lhs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->_type == AQL_NODE_OPERATOR_BINARY_OR) {
|
|
||||||
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
|
||||||
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
|
||||||
TRI_aql_logical_e nextOperator;
|
|
||||||
|
|
||||||
assert(lhs);
|
|
||||||
assert(rhs);
|
|
||||||
|
|
||||||
// recurse into next level
|
|
||||||
nextOperator = SubOperator(TRI_AQL_LOGICAL_OR, logicalType);
|
|
||||||
TRI_InspectConditionAql(context, nextOperator, lhs);
|
|
||||||
TRI_InspectConditionAql(context, nextOperator, rhs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->_type == AQL_NODE_OPERATOR_BINARY_AND) {
|
|
||||||
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
|
||||||
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
|
||||||
TRI_aql_logical_e nextOperator;
|
|
||||||
|
|
||||||
assert(lhs);
|
|
||||||
assert(rhs);
|
|
||||||
|
|
||||||
// recurse into next level
|
|
||||||
nextOperator = SubOperator(TRI_AQL_LOGICAL_AND, logicalType);
|
|
||||||
TRI_InspectConditionAql(context, nextOperator, lhs);
|
|
||||||
TRI_InspectConditionAql(context, nextOperator, rhs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->_type == AQL_NODE_OPERATOR_BINARY_EQ ||
|
|
||||||
// node->_type == AQL_NODE_OPERATOR_BINARY_NE ||
|
|
||||||
node->_type == AQL_NODE_OPERATOR_BINARY_LT ||
|
|
||||||
node->_type == AQL_NODE_OPERATOR_BINARY_LE ||
|
|
||||||
node->_type == AQL_NODE_OPERATOR_BINARY_GT ||
|
|
||||||
node->_type == AQL_NODE_OPERATOR_BINARY_GE ||
|
|
||||||
node->_type == AQL_NODE_OPERATOR_BINARY_IN) {
|
|
||||||
TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0);
|
|
||||||
TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1);
|
|
||||||
|
|
||||||
if (lhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) {
|
|
||||||
TRI_aql_attribute_name_t* field = GetAttributeName(context, lhs);
|
|
||||||
|
|
||||||
if (field) {
|
|
||||||
NoteAttributeAccess(context, logicalType, field, node->_type, rhs);
|
|
||||||
TRI_DestroyStringBuffer(&field->_name);
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (rhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) {
|
|
||||||
TRI_aql_attribute_name_t* field = GetAttributeName(context, rhs);
|
|
||||||
|
|
||||||
if (field) {
|
|
||||||
NoteAttributeAccess(context, logicalType, field, node->_type, lhs);
|
|
||||||
TRI_DestroyStringBuffer(&field->_name);
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @}
|
/// @}
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -59,8 +59,7 @@ extern "C" {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TRI_AQL_LOGICAL_AND,
|
TRI_AQL_LOGICAL_AND,
|
||||||
TRI_AQL_LOGICAL_OR,
|
TRI_AQL_LOGICAL_OR
|
||||||
TRI_AQL_LOGICAL_NOT
|
|
||||||
}
|
}
|
||||||
TRI_aql_logical_e;
|
TRI_aql_logical_e;
|
||||||
|
|
||||||
|
@ -135,31 +134,6 @@ TRI_aql_attribute_name_t;
|
||||||
/// @}
|
/// @}
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- constructors / destructors
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @addtogroup Ahuacatl
|
|
||||||
/// @{
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief init the optimizer
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool TRI_InitOptimizerAql (TRI_aql_context_t* const);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief shutdown the optimizer
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void TRI_FreeOptimizerAql (TRI_aql_context_t* const);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @}
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public functions
|
// --SECTION-- public functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -173,15 +147,15 @@ void TRI_FreeOptimizerAql (TRI_aql_context_t* const);
|
||||||
/// @brief dump ranges found for debugging purposes
|
/// @brief dump ranges found for debugging purposes
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_DumpRangesAql (TRI_aql_context_t* const);
|
void TRI_DumpRangesAql (const TRI_vector_pointer_t* const);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief inspect a condition and note all accesses found for it
|
/// @brief inspect a condition and note all accesses found for it
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_InspectConditionAql (TRI_aql_context_t* const,
|
TRI_vector_pointer_t* TRI_InspectConditionAql (TRI_aql_context_t* const,
|
||||||
const TRI_aql_logical_e,
|
TRI_aql_node_t*,
|
||||||
TRI_aql_node_t*);
|
const TRI_vector_pointer_t* const);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
#include "V8/v8-execution.h"
|
#include "V8/v8-execution.h"
|
||||||
|
|
||||||
#undef RANGE_OPTIMIZER
|
#undef RANGE_OPTIMIZER
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private functions
|
// --SECTION-- private functions
|
||||||
|
@ -268,7 +268,12 @@ static TRI_aql_node_t* OptimiseFilter (TRI_aql_context_t* const context,
|
||||||
|
|
||||||
if (!TRI_IsConstantValueNodeAql(expression)) {
|
if (!TRI_IsConstantValueNodeAql(expression)) {
|
||||||
#ifdef RANGE_OPTIMIZER
|
#ifdef RANGE_OPTIMIZER
|
||||||
TRI_InspectConditionAql(context, TRI_AQL_LOGICAL_AND, expression);
|
TRI_vector_pointer_t* ranges = TRI_InspectConditionAql(context, expression, NULL);
|
||||||
|
|
||||||
|
if (ranges) {
|
||||||
|
TRI_DumpRangesAql(ranges);
|
||||||
|
TRI_FreeVectorPointer(TRI_UNKNOWN_MEM_ZONE, ranges);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -663,13 +668,6 @@ TRI_aql_node_t* TRI_FoldConstantsAql (TRI_aql_context_t* const context,
|
||||||
TRI_aql_node_t* node) {
|
TRI_aql_node_t* node) {
|
||||||
TRI_aql_modify_tree_walker_t* walker;
|
TRI_aql_modify_tree_walker_t* walker;
|
||||||
|
|
||||||
#ifdef RANGE_OPTIMIZER
|
|
||||||
if (!TRI_InitOptimizerAql(context)) {
|
|
||||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
walker = TRI_CreateModifyTreeWalkerAql((void*) context, &ModifyNode);
|
walker = TRI_CreateModifyTreeWalkerAql((void*) context, &ModifyNode);
|
||||||
if (!walker) {
|
if (!walker) {
|
||||||
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
|
||||||
|
@ -680,10 +678,6 @@ TRI_aql_node_t* TRI_FoldConstantsAql (TRI_aql_context_t* const context,
|
||||||
|
|
||||||
TRI_FreeModifyTreeWalkerAql(walker);
|
TRI_FreeModifyTreeWalkerAql(walker);
|
||||||
|
|
||||||
#ifdef RANGE_OPTIMIZER
|
|
||||||
TRI_DumpRangesAql(context);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
context->_vocbase = vocbase;
|
context->_vocbase = vocbase;
|
||||||
context->_ranges = NULL;
|
|
||||||
|
|
||||||
context->_variableIndex = 0;
|
context->_variableIndex = 0;
|
||||||
|
|
||||||
|
@ -164,9 +163,6 @@ void TRI_FreeContextAql (TRI_aql_context_t* const context) {
|
||||||
}
|
}
|
||||||
TRI_DestroyVectorPointer(&context->_scopes);
|
TRI_DestroyVectorPointer(&context->_scopes);
|
||||||
|
|
||||||
// free range optimizer
|
|
||||||
TRI_FreeOptimizerAql(context);
|
|
||||||
|
|
||||||
// free all strings registered
|
// free all strings registered
|
||||||
i = context->_strings._length;
|
i = context->_strings._length;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
|
|
|
@ -82,7 +82,6 @@ typedef struct TRI_aql_context_s {
|
||||||
TRI_associative_pointer_t _parameterValues;
|
TRI_associative_pointer_t _parameterValues;
|
||||||
TRI_associative_pointer_t _parameterNames;
|
TRI_associative_pointer_t _parameterNames;
|
||||||
TRI_associative_pointer_t _collectionNames;
|
TRI_associative_pointer_t _collectionNames;
|
||||||
TRI_associative_pointer_t* _ranges;
|
|
||||||
size_t _variableIndex;
|
size_t _variableIndex;
|
||||||
void* _first;
|
void* _first;
|
||||||
char* _query;
|
char* _query;
|
||||||
|
|
Loading…
Reference in New Issue