diff --git a/Ahuacatl/ahuacatl-access-optimizer.c b/Ahuacatl/ahuacatl-access-optimizer.c index 020b8ee582..bbf12f8245 100644 --- a/Ahuacatl/ahuacatl-access-optimizer.c +++ b/Ahuacatl/ahuacatl-access-optimizer.c @@ -126,9 +126,6 @@ static void FreeAccess (TRI_aql_context_t* const context, TRI_aql_field_access_t* const fieldAccess) { assert(fieldAccess); - // remove from hash first - TRI_RemoveKeyAssociativePointer(&context->_ranges, fieldAccess->_fieldName); - FreeAccessMembers(fieldAccess); TRI_Free(TRI_UNKNOWN_MEM_ZONE, fieldAccess->_fieldName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, fieldAccess); @@ -300,7 +297,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } FreeAccessMembers(lhs); - FreeAccessMembers(rhs); + FreeAccess(context, rhs); if (merged->_value._objects._length > 0) { // merged list is not empty @@ -308,6 +305,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } else { // merged list is empty + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, merged); lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; } @@ -341,7 +339,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } FreeAccessMembers(lhs); - FreeAccessMembers(rhs); + FreeAccess(context, rhs); if (listInRange->_value._objects._length > 0) { // merged list is not empty @@ -349,6 +347,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } else { // merged list is empty + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, listInRange); lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; } @@ -373,7 +372,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } FreeAccessMembers(lhs); - FreeAccessMembers(rhs); + FreeAccess(context, rhs); if (listInRange->_value._objects._length > 0) { // merged list is not empty @@ -381,6 +380,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context, } else { // merged list is empty + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, listInRange); lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; } @@ -929,7 +929,7 @@ static TRI_aql_field_access_t* MergeOrList (TRI_aql_context_t* const context, } FreeAccessMembers(lhs); - FreeAccessMembers(rhs); + FreeAccess(context, rhs); if (merged->_value._objects._length > 0) { // merged list is not empty @@ -937,6 +937,7 @@ static TRI_aql_field_access_t* MergeOrList (TRI_aql_context_t* const context, } else { // merged list is empty + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, merged); lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; } @@ -1081,8 +1082,10 @@ static TRI_aql_field_access_t* MergeAccess (TRI_aql_context_t* const context, const TRI_aql_logical_e logicalType, TRI_aql_field_access_t* lhs, TRI_aql_field_access_t* rhs) { + assert(context); assert(lhs); assert(rhs); + assert(logicalType == TRI_AQL_LOGICAL_AND || logicalType == TRI_AQL_LOGICAL_OR); assert(lhs->_fieldName != NULL); assert(rhs->_fieldName != NULL); @@ -1146,6 +1149,7 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con TRI_aql_field_access_t* fieldAccess; TRI_json_t* value; + assert(context); assert(field); assert(field->_name._buffer); assert(node); @@ -1232,6 +1236,9 @@ static void NoteAttributeAccess (TRI_aql_context_t* const context, const TRI_aql_node_t* const node) { TRI_aql_field_access_t* previous; TRI_aql_field_access_t* fieldAccess; + + assert(logicalType == TRI_AQL_LOGICAL_AND || logicalType == TRI_AQL_LOGICAL_OR); + assert(node); if (!field || !field->_name._buffer) { return; @@ -1245,12 +1252,16 @@ static void NoteAttributeAccess (TRI_aql_context_t* const context, } // look up previous range first - previous = (TRI_aql_field_access_t*) TRI_LookupByKeyAssociativePointer(&context->_ranges, fieldAccess->_fieldName); + 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 - TRI_aql_field_access_t* merged = MergeAccess(context, logicalType, fieldAccess, previous); + merged = MergeAccess(context, logicalType, fieldAccess, previous); if (!merged) { // OOM @@ -1258,11 +1269,11 @@ static void NoteAttributeAccess (TRI_aql_context_t* const context, return; } - TRI_InsertKeyAssociativePointer(&context->_ranges, merged->_fieldName, merged, true); + 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); + TRI_InsertKeyAssociativePointer(context->_ranges, fieldAccess->_fieldName, fieldAccess, false); } } @@ -1273,6 +1284,9 @@ static void NoteAttributeAccess (TRI_aql_context_t* const context, static TRI_aql_attribute_name_t* GetAttributeName (TRI_aql_context_t* const context, const TRI_aql_node_t* const node) { + assert(context); + assert(node); + if (node->_type == AQL_NODE_ATTRIBUTE_ACCESS) { TRI_aql_attribute_name_t* field = GetAttributeName(context, TRI_AQL_NODE_MEMBER(node, 0)); @@ -1309,6 +1323,70 @@ static TRI_aql_attribute_name_t* GetAttributeName (TRI_aql_context_t* const cont /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief init the optimizer +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_InitOptimizerAql (TRI_aql_context_t* const context) { + assert(context); + assert(context->_ranges == NULL); + + context->_ranges = (TRI_associative_pointer_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_associative_pointer_t), false); + if (!context->_ranges) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return false; + } + + TRI_InitAssociativePointer(context->_ranges, + TRI_UNKNOWN_MEM_ZONE, + &TRI_HashStringKeyAssociativePointer, + &HashFieldAccess, + &EqualFieldAccess, + NULL); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief shutdown the optimizer +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeOptimizerAql (TRI_aql_context_t* const context) { + assert(context); + + if (context->_ranges) { + size_t i, n; + + // free all remaining access elements + n = context->_ranges->_nrAlloc; + for (i = 0; i < n; ++i) { + TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) context->_ranges->_table[i]; + if (!fieldAccess) { + continue; + } + + FreeAccess(context, fieldAccess); + } + + // free hash array + TRI_FreeAssociativePointer(TRI_UNKNOWN_MEM_ZONE, context->_ranges); + context->_ranges = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -1324,9 +1402,11 @@ static TRI_aql_attribute_name_t* GetAttributeName (TRI_aql_context_t* const cont void TRI_DumpRangesAql (TRI_aql_context_t* const context) { size_t i; + + assert(context); - for (i = 0; i < context->_ranges._nrAlloc; ++i) { - TRI_aql_field_access_t* fieldAccess = context->_ranges._table[i]; + for (i = 0; i < context->_ranges->_nrAlloc; ++i) { + TRI_aql_field_access_t* fieldAccess = context->_ranges->_table[i]; if (!fieldAccess) { continue; @@ -1340,6 +1420,7 @@ void TRI_DumpRangesAql (TRI_aql_context_t* const context) { TRI_StringifyJson(&b, fieldAccess->_value._value); printf("- VALUE: %s\n", b._buffer); + TRI_DestroyStringBuffer(&b); } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { TRI_string_buffer_t b; @@ -1347,6 +1428,7 @@ void TRI_DumpRangesAql (TRI_aql_context_t* const context) { TRI_StringifyJson(&b, fieldAccess->_value._singleRange._value); printf("- VALUE: %s\n", b._buffer); + TRI_DestroyStringBuffer(&b); } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { TRI_string_buffer_t b; @@ -1356,24 +1438,11 @@ void TRI_DumpRangesAql (TRI_aql_context_t* const context) { TRI_StringifyJson(&b, fieldAccess->_value._between._upper._value); printf("- VALUE: %s\n", b._buffer); + TRI_DestroyStringBuffer(&b); } } } -//////////////////////////////////////////////////////////////////////////////// -/// @brief init the optimizer -//////////////////////////////////////////////////////////////////////////////// - -void TRI_InitOptimizerAql (TRI_aql_context_t* const context) { - // TODO: must free - TRI_InitAssociativePointer(&context->_ranges, - TRI_UNKNOWN_MEM_ZONE, - &TRI_HashStringKeyAssociativePointer, - &HashFieldAccess, - &EqualFieldAccess, - NULL); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief inspect a condition and note all accesses found for it //////////////////////////////////////////////////////////////////////////////// diff --git a/Ahuacatl/ahuacatl-access-optimizer.h b/Ahuacatl/ahuacatl-access-optimizer.h index c3dc8e926d..17d22c8551 100644 --- a/Ahuacatl/ahuacatl-access-optimizer.h +++ b/Ahuacatl/ahuacatl-access-optimizer.h @@ -134,6 +134,31 @@ 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 // ----------------------------------------------------------------------------- @@ -149,12 +174,6 @@ TRI_aql_attribute_name_t; void TRI_DumpRangesAql (TRI_aql_context_t* const); -//////////////////////////////////////////////////////////////////////////////// -/// @brief init the optimizer -//////////////////////////////////////////////////////////////////////////////// - -void TRI_InitOptimizerAql (TRI_aql_context_t* const); - //////////////////////////////////////////////////////////////////////////////// /// @brief inspect a condition and note all accesses found for it //////////////////////////////////////////////////////////////////////////////// diff --git a/Ahuacatl/ahuacatl-constant-folder.c b/Ahuacatl/ahuacatl-constant-folder.c index b0b4615f06..ee67302e00 100644 --- a/Ahuacatl/ahuacatl-constant-folder.c +++ b/Ahuacatl/ahuacatl-constant-folder.c @@ -31,7 +31,7 @@ #include "V8/v8-execution.h" -#undef RANGE_OPTIMIZER +#undef RANGE_OPTIMIZER // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -660,7 +660,10 @@ TRI_aql_node_t* TRI_FoldConstantsAql (TRI_aql_context_t* const context, TRI_aql_modify_tree_walker_t* walker; #ifdef RANGE_OPTIMIZER - TRI_InitOptimizerAql(context); + if (!TRI_InitOptimizerAql(context)) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return node; + } #endif walker = TRI_CreateModifyTreeWalkerAql((void*) context, &ModifyNode); diff --git a/Ahuacatl/ahuacatl-context.c b/Ahuacatl/ahuacatl-context.c index 471685d90b..ed245d983b 100644 --- a/Ahuacatl/ahuacatl-context.c +++ b/Ahuacatl/ahuacatl-context.c @@ -26,6 +26,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "Ahuacatl/ahuacatl-context.h" +#include "Ahuacatl/ahuacatl-access-optimizer.h" #include "Ahuacatl/ahuacatl-ast-node.h" #include "Ahuacatl/ahuacatl-bind-parameter.h" #include "Ahuacatl/ahuacatl-collections.h" @@ -77,6 +78,8 @@ TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase, } context->_vocbase = vocbase; + context->_ranges = NULL; + context->_variableIndex = 0; // actual bind parameter values @@ -161,6 +164,9 @@ void TRI_FreeContextAql (TRI_aql_context_t* const context) { } TRI_DestroyVectorPointer(&context->_scopes); + // free range optimizer + TRI_FreeOptimizerAql(context); + // free all strings registered i = context->_strings._length; while (i--) { diff --git a/Ahuacatl/ahuacatl-context.h b/Ahuacatl/ahuacatl-context.h index a069040839..3890f93f83 100644 --- a/Ahuacatl/ahuacatl-context.h +++ b/Ahuacatl/ahuacatl-context.h @@ -82,7 +82,7 @@ typedef struct TRI_aql_context_s { TRI_associative_pointer_t _parameterValues; TRI_associative_pointer_t _parameterNames; TRI_associative_pointer_t _collectionNames; - TRI_associative_pointer_t _ranges; + TRI_associative_pointer_t* _ranges; size_t _variableIndex; void* _first; char* _query; diff --git a/Ahuacatl/ahuacatl-conversions.c b/Ahuacatl/ahuacatl-conversions.c index cb3c8a39b6..64a0bd3660 100644 --- a/Ahuacatl/ahuacatl-conversions.c +++ b/Ahuacatl/ahuacatl-conversions.c @@ -89,7 +89,12 @@ TRI_json_t* TRI_NodeJsonAql (TRI_aql_context_t* const context, if (result) { n = node->_members._length; for (i = 0; i < n; ++i) { - TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(node, i))); + TRI_json_t* subValue = TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(node, i)); + + if (subValue) { + TRI_PushBack2ListJson(result, subValue); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, subValue); + } } } return result; @@ -102,7 +107,15 @@ TRI_json_t* TRI_NodeJsonAql (TRI_aql_context_t* const context, n = node->_members._length; for (i = 0; i < n; ++i) { TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(node, i); - TRI_InsertArrayJson(TRI_UNKNOWN_MEM_ZONE, result, TRI_AQL_NODE_STRING(element), TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(element, 0))); + TRI_json_t* subValue = TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(element, 0)); + + if (subValue) { + TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, + result, + TRI_AQL_NODE_STRING(element), + subValue); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, subValue); + } } } return result; diff --git a/Ahuacatl/ahuacatl-error.c b/Ahuacatl/ahuacatl-error.c index a442441161..649f070b07 100644 --- a/Ahuacatl/ahuacatl-error.c +++ b/Ahuacatl/ahuacatl-error.c @@ -141,6 +141,8 @@ char* TRI_GetContextErrorAql (const char* const query, const size_t line, const size_t currentLine = 1; size_t currentColumn = 1; const char* p = query; + char* temp; + char* result; size_t offset; char c; @@ -169,7 +171,16 @@ char* TRI_GetContextErrorAql (const char* const query, const size_t line, const return TRI_DuplicateString2(query + offset, strlen(query) - offset); } - return TRI_Concatenate2String(TRI_DuplicateString2(query + offset, SNIPPET_LENGTH), SNIPPET_SUFFIX); + temp = TRI_DuplicateString2(query + offset, SNIPPET_LENGTH); + if (!temp) { + // out of memory + return NULL; + } + + result = TRI_Concatenate2String(temp, SNIPPET_SUFFIX); + TRI_FreeString(TRI_CORE_MEM_ZONE, temp); + + return result; } ////////////////////////////////////////////////////////////////////////////////