From 9ae4a041a282ca9f255b5fd2c6431a02ed22f5d5 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 7 May 2012 11:51:16 +0200 Subject: [PATCH 1/4] remove constant sort expressions, remove constant true filter expressions, remove constant relational expressions --- Ahuacatl/ahuacatl-constant-folder.c | 242 ++++++++++++++++++++++++++-- Ahuacatl/ahuacatl-constant-folder.h | 1 + Ahuacatl/ahuacatl-tree-walker.c | 29 +++- 3 files changed, 255 insertions(+), 17 deletions(-) diff --git a/Ahuacatl/ahuacatl-constant-folder.c b/Ahuacatl/ahuacatl-constant-folder.c index 90aaac5773..36e600c526 100644 --- a/Ahuacatl/ahuacatl-constant-folder.c +++ b/Ahuacatl/ahuacatl-constant-folder.c @@ -41,11 +41,62 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief create code for a function call +/// @brief create javascript function code for a relational operation //////////////////////////////////////////////////////////////////////////////// -static TRI_string_buffer_t* FcallCode(const char* const name, - const TRI_aql_node_t* const args) { +static TRI_string_buffer_t* RelationCode (const char* const name, + const TRI_aql_node_t* const lhs, + const TRI_aql_node_t* const rhs) { + TRI_string_buffer_t* buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE); + + if (!lhs || !rhs) { + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, "(function(){return AHUACATL_RELATIONAL_") != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, name) != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, "(") != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (!TRI_NodeJavascriptAql(buffer, lhs)) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendCharStringBuffer(buffer, ',') != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (!TRI_NodeJavascriptAql(buffer, rhs)) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, ");})") != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + return buffer; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create javascript function code for a function call +//////////////////////////////////////////////////////////////////////////////// + +static TRI_string_buffer_t* FcallCode (const char* const name, + const TRI_aql_node_t* const args) { TRI_string_buffer_t* buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE); size_t i; size_t n; @@ -98,8 +149,8 @@ static TRI_string_buffer_t* FcallCode(const char* const name, //////////////////////////////////////////////////////////////////////////////// static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context, - TRI_aql_node_t* node) { - TRI_aql_node_t* args = (TRI_aql_node_t*) node->_members._buffer[0]; + TRI_aql_node_t* node) { + TRI_aql_node_t* args = TRI_AQL_NODE_MEMBER(node, 0); TRI_aql_function_t* function; TRI_js_exec_context_t* execContext; TRI_string_buffer_t* code; @@ -126,12 +177,14 @@ static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context, } // all arguments are constants + // create the function code code = FcallCode(function->_internalName, args); if (!code) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return node; } - + + // execute the function code execContext = TRI_CreateExecutionContext(code->_buffer); TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, code); @@ -147,9 +200,82 @@ static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context, return NULL; } + // use the constant values instead of the function call node node = TRI_JsonNodeAql(context, json); + if (!node) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + } TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + + LOG_TRACE("optimised function call"); + + return node; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief optimise a sort expression +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* OptimiseSort (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + TRI_aql_node_t* list = TRI_AQL_NODE_MEMBER(node, 0); + size_t i, n; + + if (!list) { + return node; + } + + i = 0; + n = list->_members._length; + while (i < n) { + // sort element + TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(list, i); + TRI_aql_node_t* expression = TRI_AQL_NODE_MEMBER(element, 0); + + // check if the sort element is constant + if (!expression || !TRI_IsConstantValueNodeAql(expression)) { + ++i; + continue; + } + + // sort element is constant so it can be removed + TRI_RemoveVectorPointer(&list->_members, i); + --n; + + LOG_TRACE("optimised away sort element"); + } + + if (n == 0) { + // no members left => sort removed + LOG_TRACE("optimised away sort"); + + return NULL; + } + + return node; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief optimise a filter expression +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* OptimiseFilter (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + TRI_aql_node_t* expression = TRI_AQL_NODE_MEMBER(node, 0); + bool result; + + if (!expression || !TRI_IsConstantValueNodeAql(expression)) { + return node; + } + + result = TRI_GetBooleanNodeValueAql(expression); + if (result) { + // filter expression is always true => remove it + LOG_TRACE("optimised away constant filter"); + + return NULL; + } return node; } @@ -159,8 +285,8 @@ static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context, //////////////////////////////////////////////////////////////////////////////// static TRI_aql_node_t* OptimiseUnaryArithmeticOperation (TRI_aql_context_t* const context, - TRI_aql_node_t* node) { - TRI_aql_node_t* operand = (TRI_aql_node_t*) node->_members._buffer[0]; + TRI_aql_node_t* node) { + TRI_aql_node_t* operand = TRI_AQL_NODE_MEMBER(node, 0); if (!operand || !TRI_IsConstantValueNodeAql(operand)) { return node; @@ -195,7 +321,7 @@ static TRI_aql_node_t* OptimiseUnaryArithmeticOperation (TRI_aql_context_t* cons static TRI_aql_node_t* OptimiseUnaryLogicalOperation (TRI_aql_context_t* const context, TRI_aql_node_t* node) { - TRI_aql_node_t* operand = (TRI_aql_node_t*) node->_members._buffer[0]; + TRI_aql_node_t* operand = TRI_AQL_NODE_MEMBER(node, 0); if (!operand || !TRI_IsConstantValueNodeAql(operand)) { return node; @@ -214,6 +340,8 @@ static TRI_aql_node_t* OptimiseUnaryLogicalOperation (TRI_aql_context_t* const c if (!node) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); } + + LOG_TRACE("optimised away unary logical operation"); } return node; @@ -225,8 +353,8 @@ static TRI_aql_node_t* OptimiseUnaryLogicalOperation (TRI_aql_context_t* const c static TRI_aql_node_t* OptimiseBinaryLogicalOperation (TRI_aql_context_t* const context, TRI_aql_node_t* node) { - TRI_aql_node_t* lhs = (TRI_aql_node_t*) node->_members._buffer[0]; - TRI_aql_node_t* rhs = (TRI_aql_node_t*) node->_members._buffer[1]; + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); bool isEligibleLhs; bool isEligibleRhs; bool lhsValue; @@ -257,6 +385,8 @@ static TRI_aql_node_t* OptimiseBinaryLogicalOperation (TRI_aql_context_t* const assert(node->_type == AQL_NODE_OPERATOR_BINARY_AND || node->_type == AQL_NODE_OPERATOR_BINARY_OR); + LOG_TRACE("optimised away binary logical operation"); + if (node->_type == AQL_NODE_OPERATOR_BINARY_AND) { if (lhsValue) { // if (true && rhs) => rhs @@ -281,14 +411,86 @@ static TRI_aql_node_t* OptimiseBinaryLogicalOperation (TRI_aql_context_t* const return node; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief optimise a relational operation with two operands +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* OptimiseBinaryRelationalOperation (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); + TRI_js_exec_context_t* execContext; + TRI_string_buffer_t* code; + TRI_json_t* json; + char* func; + + if (!lhs || !TRI_IsConstantValueNodeAql(lhs) || !rhs || !TRI_IsConstantValueNodeAql(rhs)) { + return node; + } + + if (node->_type == AQL_NODE_OPERATOR_BINARY_EQ) { + func = "EQUAL"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_NE) { + func = "UNEQUAL"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_GT) { + func = "GREATER"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_GE) { + func = "GREATER_EQUAL"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_LT) { + func = "LESS"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_LE) { + func = "LESS_EQUAL"; + } + else if (node->_type == AQL_NODE_OPERATOR_BINARY_IN) { + func = "IN"; + } + + code = RelationCode(func, lhs, rhs); + if (!code) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return node; + } + + // execute the function code + execContext = TRI_CreateExecutionContext(code->_buffer); + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, code); + + if (!execContext) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return node; + } + + json = TRI_ExecuteResultContext(execContext); + TRI_FreeExecutionContext(execContext); + if (!json) { + TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_SCRIPT, NULL); + return NULL; + } + + // use the constant values instead of the function call node + node = TRI_JsonNodeAql(context, json); + if (!node) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + } + + LOG_TRACE("optimised away binary relational operation"); + + return node; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief optimise an arithmetic operation with two operands //////////////////////////////////////////////////////////////////////////////// static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* const context, TRI_aql_node_t* node) { - TRI_aql_node_t* lhs = (TRI_aql_node_t*) node->_members._buffer[0]; - TRI_aql_node_t* rhs = (TRI_aql_node_t*) node->_members._buffer[1]; + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); bool isEligibleLhs; bool isEligibleRhs; double value; @@ -350,6 +552,8 @@ static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* con TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } + + LOG_TRACE("optimised away binary arithmetic operation"); return node; } @@ -374,12 +578,24 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) { case AQL_NODE_OPERATOR_BINARY_AND: case AQL_NODE_OPERATOR_BINARY_OR: return OptimiseBinaryLogicalOperation(context, node); + case AQL_NODE_OPERATOR_BINARY_EQ: + case AQL_NODE_OPERATOR_BINARY_NE: + case AQL_NODE_OPERATOR_BINARY_LT: + case AQL_NODE_OPERATOR_BINARY_LE: + case AQL_NODE_OPERATOR_BINARY_GT: + case AQL_NODE_OPERATOR_BINARY_GE: + case AQL_NODE_OPERATOR_BINARY_IN: + return OptimiseBinaryRelationalOperation(context, node); case AQL_NODE_OPERATOR_BINARY_PLUS: case AQL_NODE_OPERATOR_BINARY_MINUS: case AQL_NODE_OPERATOR_BINARY_TIMES: case AQL_NODE_OPERATOR_BINARY_DIV: case AQL_NODE_OPERATOR_BINARY_MOD: return OptimiseBinaryArithmeticOperation(context, node); + case AQL_NODE_SORT: + return OptimiseSort(context, node); + case AQL_NODE_FILTER: + return OptimiseFilter(context, node); case AQL_NODE_FCALL: return OptimiseFcall(context, node); default: diff --git a/Ahuacatl/ahuacatl-constant-folder.h b/Ahuacatl/ahuacatl-constant-folder.h index 3593f9033a..4788df1d1b 100644 --- a/Ahuacatl/ahuacatl-constant-folder.h +++ b/Ahuacatl/ahuacatl-constant-folder.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff --git a/Ahuacatl/ahuacatl-tree-walker.c b/Ahuacatl/ahuacatl-tree-walker.c index 0d183e80ce..2ae01c1155 100644 --- a/Ahuacatl/ahuacatl-tree-walker.c +++ b/Ahuacatl/ahuacatl-tree-walker.c @@ -42,11 +42,13 @@ static TRI_aql_node_t* ModifyNode (TRI_aql_modify_tree_walker_t* const walker, TRI_aql_node_t* node) { - TRI_aql_node_t* result = NULL; + TRI_aql_node_t* first = NULL; + TRI_aql_node_t* last = NULL; assert(walker); while (node) { + TRI_aql_node_t* old; size_t i; size_t n = node->_members._length; @@ -60,19 +62,38 @@ static TRI_aql_node_t* ModifyNode (TRI_aql_modify_tree_walker_t* const walker, node->_members._buffer[i] = ModifyNode(walker, member); } + + // keep old node pointer + old = node; // the visit function might set it to NULL node = walker->visitFunc(walker->_data, node); - if (!result) { - result = node; + if (!first) { + // first remaining node in chain + first = node; + } + + if (last) { + // keep node chaining intact + last->_next = node; } if (node) { + last = node; + } + + // determine next next in chain + if (node == old) { + // node did not change node = node->_next; } + else if (node != old && old != NULL) { + // node changed + node = old->_next; + } } - return result; + return first; } //////////////////////////////////////////////////////////////////////////////// From 07db7dd731f994d06e75c1b7cee4c42623be3de4 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 7 May 2012 13:28:16 +0200 Subject: [PATCH 2/4] more descriptive error messages --- Ahuacatl/ahuacatl-codegen-js.c | 3 ++- BasicsC/errors.dat | 4 ++-- BasicsC/voc-errors.c | 4 ++-- BasicsC/voc-errors.h | 8 ++++---- V8/v8-vocbase.cpp | 31 +++++++++++++++---------------- js/common/bootstrap/errors.js | 4 ++-- js/common/bootstrap/js-errors.h | 4 ++-- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Ahuacatl/ahuacatl-codegen-js.c b/Ahuacatl/ahuacatl-codegen-js.c index 3f91326c1e..ba1f81c146 100644 --- a/Ahuacatl/ahuacatl-codegen-js.c +++ b/Ahuacatl/ahuacatl-codegen-js.c @@ -1667,6 +1667,7 @@ char* TRI_GenerateCodeAql (const void* const data) { OutputString(&generator->_buffer, REGISTER_PREFIX); OutputInt(&generator->_buffer, (int64_t) resultRegister); OutputString(&generator->_buffer, ";\n"); + OutputString(&generator->_buffer, "})()"); if (generator->_error) { @@ -1681,7 +1682,7 @@ char* TRI_GenerateCodeAql (const void* const data) { if (code) { LOG_TRACE("generated code: %s", code); -// printf("generated code: %s", code); + // printf("generated code: %s", code); } return code; diff --git a/BasicsC/errors.dat b/BasicsC/errors.dat index 9f372b5abc..1c70a56988 100644 --- a/BasicsC/errors.dat +++ b/BasicsC/errors.dat @@ -99,7 +99,7 @@ ERROR_AVOCADO_DATAFILE_FULL,1300,"datafile full","Will be raised when the datafi ################################################################################ ERROR_QUERY_KILLED,1500,"query killed","Will be raised when a running query is killed by an explicit admin command." -ERROR_QUERY_PARSE,1501,"parse error: %s","Will be raised when query is parsed and is found to be syntactially invalid." +ERROR_QUERY_PARSE,1501,"%s","Will be raised when query is parsed and is found to be syntactially invalid." ERROR_QUERY_EMPTY,1502,"query is empty","Will be raised when an empty query is specified." ERROR_QUERY_SPECIFICATION_INVALID,1503,"query specification invalid","Will be raised when a query is sent to the server with an incomplete or invalid query specification structure." ERROR_QUERY_NUMBER_OUT_OF_RANGE,1504,"number '%s' is out of range","Will be raised when a numeric value inside a query is out of the allowed value range." @@ -117,7 +117,7 @@ ERROR_QUERY_BIND_PARAMETER_UNDECLARED,1515,"bind parameter '%s' was not declared ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID,1516,"invalid value for bind parameter '%s'","Will be raised when an invalid value is specified for one of the bind parameters." ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE,1517,"bind parameter number '%s' out of range","Will be specified when the numeric index for a bind parameter of type @n is out of the allowed range." ERROR_QUERY_FUNCTION_NAME_UNKNOWN,1518,"usage of unknown function '%s'","Will be raised when an undefined function is called." -ERROR_QUERY_RUNTIME_ERROR,1520,"runtime error in query","Will be raised when a Javascript runtime error occurs while executing a query." +ERROR_QUERY_RUNTIME_ERROR,1520,"runtime error '%s'","Will be raised when a Javascript runtime error occurs while executing a query." ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE,1521,"limit value '%s' is out of range","Will be raised when a limit value in the query is outside the allowed range (e. g. when passing a negative skip value)." ERROR_QUERY_VARIABLE_REDECLARED,1522,"variable '%s' is assigned multiple times","Will be raised when a variable gets re-assigned in a query." ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED,1523,"document attribute '%s' is assigned multiple times","Will be raised when a document attribute is re-assigned." diff --git a/BasicsC/voc-errors.c b/BasicsC/voc-errors.c index 31a36a8c50..554a2cc51e 100644 --- a/BasicsC/voc-errors.c +++ b/BasicsC/voc-errors.c @@ -65,7 +65,7 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_AVOCADO_CAP_CONSTRAINT_ALREADY_DEFINED, "cap constraint already defined"); REG_ERROR(ERROR_AVOCADO_DATAFILE_FULL, "datafile full"); REG_ERROR(ERROR_QUERY_KILLED, "query killed"); - REG_ERROR(ERROR_QUERY_PARSE, "parse error: %s"); + REG_ERROR(ERROR_QUERY_PARSE, "%s"); REG_ERROR(ERROR_QUERY_EMPTY, "query is empty"); REG_ERROR(ERROR_QUERY_SPECIFICATION_INVALID, "query specification invalid"); REG_ERROR(ERROR_QUERY_NUMBER_OUT_OF_RANGE, "number '%s' is out of range"); @@ -83,7 +83,7 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID, "invalid value for bind parameter '%s'"); REG_ERROR(ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE, "bind parameter number '%s' out of range"); REG_ERROR(ERROR_QUERY_FUNCTION_NAME_UNKNOWN, "usage of unknown function '%s'"); - REG_ERROR(ERROR_QUERY_RUNTIME_ERROR, "runtime error in query"); + REG_ERROR(ERROR_QUERY_RUNTIME_ERROR, "runtime error '%s'"); REG_ERROR(ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE, "limit value '%s' is out of range"); REG_ERROR(ERROR_QUERY_VARIABLE_REDECLARED, "variable '%s' is assigned multiple times"); REG_ERROR(ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED, "document attribute '%s' is assigned multiple times"); diff --git a/BasicsC/voc-errors.h b/BasicsC/voc-errors.h index e1f2244515..aeaf3a46eb 100644 --- a/BasicsC/voc-errors.h +++ b/BasicsC/voc-errors.h @@ -130,7 +130,7 @@ extern "C" { /// - 1500: @CODE{query killed} /// Will be raised when a running query is killed by an explicit admin /// command. -/// - 1501: @CODE{parse error: \%s} +/// - 1501: @CODE{\%s} /// Will be raised when query is parsed and is found to be syntactially /// invalid. /// - 1502: @CODE{query is empty} @@ -180,7 +180,7 @@ extern "C" { /// is out of the allowed range. /// - 1518: @CODE{usage of unknown function '\%s'} /// Will be raised when an undefined function is called. -/// - 1520: @CODE{runtime error in query} +/// - 1520: @CODE{runtime error '\%s'} /// Will be raised when a Javascript runtime error occurs while executing a /// query. /// - 1521: @CODE{limit value '\%s' is out of range} @@ -891,7 +891,7 @@ void TRI_InitialiseErrorMessages (void); //////////////////////////////////////////////////////////////////////////////// /// @brief 1501: ERROR_QUERY_PARSE /// -/// parse error: %s +/// %s /// /// Will be raised when query is parsed and is found to be syntactially invalid. //////////////////////////////////////////////////////////////////////////////// @@ -1083,7 +1083,7 @@ void TRI_InitialiseErrorMessages (void); //////////////////////////////////////////////////////////////////////////////// /// @brief 1520: ERROR_QUERY_RUNTIME_ERROR /// -/// runtime error in query +/// runtime error '%s' /// /// Will be raised when a Javascript runtime error occurs while executing a /// query. diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index 846afe06af..f5f1a6f97d 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -279,7 +279,13 @@ static v8::Handle CreateErrorObject (int errorNumber, string const& v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData(); - string msg = TRI_errno_string(errorNumber) + string(": ") + message; + string msg; + if (message.size()) { + msg = message; + } + else { + msg = TRI_errno_string(errorNumber) + string(": ") + message; + } v8::Handle errorMessage = v8::String::New(msg.c_str()); v8::Handle errorObject = v8::Exception::Error(errorMessage)->ToObject(); @@ -287,6 +293,7 @@ static v8::Handle CreateErrorObject (int errorNumber, string const& errorObject->Set(v8::String::New("errorNum"), v8::Number::New(errorNumber)); errorObject->Set(v8::String::New("errorMessage"), errorMessage); + errorObject->SetPrototype(proto); return errorObject; @@ -2930,6 +2937,13 @@ static v8::Handle JS_RunAhuacatl (v8::Arguments const& argv) { return scope.Close(WrapGeneralCursor(cursor)); } + if (tryCatch.HasCaught()) { + TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_RUNTIME_ERROR, TRI_ObjectToString(tryCatch.Exception()).c_str()); + v8::Handle errorObject = CreateErrorObjectAhuacatl(&context->_error); + + return scope.Close(errorObject); + } + return scope.Close(v8::ThrowException(v8::String::New("cannot create cursor"))); } @@ -6384,21 +6398,6 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas v8g->ToKey = v8::Persistent::New(v8::String::New("_to")); } - // ............................................................................. - // generate the query error template - // ............................................................................. - - ft = v8::FunctionTemplate::New(); - ft->SetClassName(v8::String::New("AvocadoError")); - - rt = ft->InstanceTemplate(); - - v8g->ErrorTempl = v8::Persistent::New(rt); - - // must come after SetInternalFieldCount - context->Global()->Set(v8::String::New("AvocadoError"), - ft->GetFunction()); - // ............................................................................. // generate the TRI_vocbase_t template // ............................................................................. diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index 606a12b651..27fa31f9cb 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -59,7 +59,7 @@ ModuleCache["/internal"].exports.errors = { "ERROR_AVOCADO_CAP_CONSTRAINT_ALREADY_DEFINED" : { "code" : 1215, "message" : "cap constraint already defined" }, "ERROR_AVOCADO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" }, "ERROR_QUERY_KILLED" : { "code" : 1500, "message" : "query killed" }, - "ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "parse error: %s" }, + "ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "%s" }, "ERROR_QUERY_EMPTY" : { "code" : 1502, "message" : "query is empty" }, "ERROR_QUERY_SPECIFICATION_INVALID" : { "code" : 1503, "message" : "query specification invalid" }, "ERROR_QUERY_NUMBER_OUT_OF_RANGE" : { "code" : 1504, "message" : "number '%s' is out of range" }, @@ -77,7 +77,7 @@ ModuleCache["/internal"].exports.errors = { "ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID" : { "code" : 1516, "message" : "invalid value for bind parameter '%s'" }, "ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE" : { "code" : 1517, "message" : "bind parameter number '%s' out of range" }, "ERROR_QUERY_FUNCTION_NAME_UNKNOWN" : { "code" : 1518, "message" : "usage of unknown function '%s'" }, - "ERROR_QUERY_RUNTIME_ERROR" : { "code" : 1520, "message" : "runtime error in query" }, + "ERROR_QUERY_RUNTIME_ERROR" : { "code" : 1520, "message" : "runtime error '%s'" }, "ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE" : { "code" : 1521, "message" : "limit value '%s' is out of range" }, "ERROR_QUERY_VARIABLE_REDECLARED" : { "code" : 1522, "message" : "variable '%s' is assigned multiple times" }, "ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED" : { "code" : 1523, "message" : "document attribute '%s' is assigned multiple times" }, diff --git a/js/common/bootstrap/js-errors.h b/js/common/bootstrap/js-errors.h index a879fdf1cf..4c8ac4d2b0 100644 --- a/js/common/bootstrap/js-errors.h +++ b/js/common/bootstrap/js-errors.h @@ -60,7 +60,7 @@ static string JS_common_bootstrap_errors = " \"ERROR_AVOCADO_CAP_CONSTRAINT_ALREADY_DEFINED\" : { \"code\" : 1215, \"message\" : \"cap constraint already defined\" }, \n" " \"ERROR_AVOCADO_DATAFILE_FULL\" : { \"code\" : 1300, \"message\" : \"datafile full\" }, \n" " \"ERROR_QUERY_KILLED\" : { \"code\" : 1500, \"message\" : \"query killed\" }, \n" - " \"ERROR_QUERY_PARSE\" : { \"code\" : 1501, \"message\" : \"parse error: %s\" }, \n" + " \"ERROR_QUERY_PARSE\" : { \"code\" : 1501, \"message\" : \"%s\" }, \n" " \"ERROR_QUERY_EMPTY\" : { \"code\" : 1502, \"message\" : \"query is empty\" }, \n" " \"ERROR_QUERY_SPECIFICATION_INVALID\" : { \"code\" : 1503, \"message\" : \"query specification invalid\" }, \n" " \"ERROR_QUERY_NUMBER_OUT_OF_RANGE\" : { \"code\" : 1504, \"message\" : \"number '%s' is out of range\" }, \n" @@ -78,7 +78,7 @@ static string JS_common_bootstrap_errors = " \"ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID\" : { \"code\" : 1516, \"message\" : \"invalid value for bind parameter '%s'\" }, \n" " \"ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE\" : { \"code\" : 1517, \"message\" : \"bind parameter number '%s' out of range\" }, \n" " \"ERROR_QUERY_FUNCTION_NAME_UNKNOWN\" : { \"code\" : 1518, \"message\" : \"usage of unknown function '%s'\" }, \n" - " \"ERROR_QUERY_RUNTIME_ERROR\" : { \"code\" : 1520, \"message\" : \"runtime error in query\" }, \n" + " \"ERROR_QUERY_RUNTIME_ERROR\" : { \"code\" : 1520, \"message\" : \"runtime error '%s'\" }, \n" " \"ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE\" : { \"code\" : 1521, \"message\" : \"limit value '%s' is out of range\" }, \n" " \"ERROR_QUERY_VARIABLE_REDECLARED\" : { \"code\" : 1522, \"message\" : \"variable '%s' is assigned multiple times\" }, \n" " \"ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED\" : { \"code\" : 1523, \"message\" : \"document attribute '%s' is assigned multiple times\" }, \n" From a4dc4e79f678dfe1a91fbefd468d6b8e433ddcf7 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 7 May 2012 14:34:51 +0200 Subject: [PATCH 3/4] re-committed memleak fix for geoindexes, this time with adjust test --- GeoIndex/GeoIndex.c | 19 +++++++++++++++++++ UnitTests/Cambridge/georeg.cpp | 23 +++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/GeoIndex/GeoIndex.c b/GeoIndex/GeoIndex.c index 5293e923e9..f9795ec554 100644 --- a/GeoIndex/GeoIndex.c +++ b/GeoIndex/GeoIndex.c @@ -555,6 +555,11 @@ GeoIndex * GeoIndex_new(void) void GeoIndex_free(GeoIndex * gi) { GeoIx * gix; + + if (gi == NULL) { + return; + } + gix = (GeoIx *) gi; free(gix->gc); free(gix->pots); @@ -785,6 +790,11 @@ GeoResults * GeoResultsCons(int alloc) GeoResults * gres; int * sa; double * dd; + + if (alloc <= 0) { + return NULL; + } + gres=malloc(sizeof(GeoResults)); sa=malloc(alloc*sizeof(int)); dd=malloc(alloc*sizeof(double)); @@ -939,8 +949,17 @@ GeoCoordinates * GeoAnswers (GeoIx * gix, GeoResults * gr) GeoCoordinate * gc; int i,j,slot; double mole; + + if (gr->pointsct == 0) { + free(gr->slot); + free(gr->snmd); + free(gr); + return NULL; + } + ans = malloc(sizeof(GeoCoordinates)); gc = malloc(gr->pointsct * sizeof(GeoCoordinate)); + if( (ans==NULL) || (gc==NULL) ) { if(ans!=NULL) free(ans); diff --git a/UnitTests/Cambridge/georeg.cpp b/UnitTests/Cambridge/georeg.cpp index ca23ec61c8..acfb784f88 100644 --- a/UnitTests/Cambridge/georeg.cpp +++ b/UnitTests/Cambridge/georeg.cpp @@ -264,6 +264,7 @@ void runTest (int mode) double la,lo; double d1; int i,j,r; + void* nullp = 0; errors=0; @@ -332,9 +333,11 @@ void runTest (int mode) /* do both searches with an empty index */ list1 = GeoIndex_NearestCountPoints(gi,&gcp1,3); - gccheck(20,list1, 0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + // gccheck(20,list1,0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + BOOST_CHECK_EQUAL(nullp, list1); // no results, check against null pointer list1 = GeoIndex_PointsWithinRadius(gi,&gcp1,100000.0); - gccheck(21,list1,0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + // gccheck(21,list1,0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + BOOST_CHECK_EQUAL(nullp, list1); // no results, check against null pointer /* stick in Jo'burg */ gcp4.data=ix + 4; @@ -349,9 +352,11 @@ void runTest (int mode) r = GeoIndex_remove(gi,&gcp4); icheck(25,0,r); list1 = GeoIndex_NearestCountPoints(gi,&gcp1,3); - gccheck(26,list1, 0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + // gccheck(26,list1, 0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + BOOST_CHECK_EQUAL(nullp, list1); // no results, check against null pointer list1 = GeoIndex_PointsWithinRadius(gi,&gcp1,100000.0); - gccheck(27,list1,0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + // gccheck(27,list1,0,"AAAAAAAAAAAAAAAAAAAAAAAAA"); + BOOST_CHECK_EQUAL(nullp, list1); // no results, check against null pointer /* try to delete from an empty index */ @@ -1037,7 +1042,10 @@ void runTest (int mode) { coonum(&gcp1,j); list1 = GeoIndex_PointsWithinRadius(gi,&gcp1,127000.0); - GeoIndex_CoordinatesFree(list1); + if (list1) { + // only free if pointer is valid + GeoIndex_CoordinatesFree(list1); + } } } BOOST_TEST_MESSAGE("End of timing test"); @@ -1052,7 +1060,10 @@ void runTest (int mode) { coonum(&gcp1,j); list1 = GeoIndex_NearestCountPoints(gi,&gcp1,2); - GeoIndex_CoordinatesFree(list1); + if (list1) { + // only free if pointer is valid + GeoIndex_CoordinatesFree(list1); + } } } BOOST_TEST_MESSAGE("End of timing test"); From 3028042ee5f0c66ebe47af0f17f5e68be17b46c9 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 7 May 2012 14:49:21 +0200 Subject: [PATCH 4/4] issue #64: moved from malloc/free to TRI_Allocate() and TRI_Free() --- GeoIndex/GeoIndex.c | 94 +++++++++++++++++++++++++++++---------------- GeoIndex/GeoIndex.h | 7 ---- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/GeoIndex/GeoIndex.c b/GeoIndex/GeoIndex.c index f9795ec554..9b9cd1ea00 100644 --- a/GeoIndex/GeoIndex.c +++ b/GeoIndex/GeoIndex.c @@ -362,20 +362,31 @@ GeoIndex * GeoIndex_new(void) int i,j; double lat, lon, x, y, z; - gix = malloc(sizeof(GeoIx)); - if(gix==NULL) return (GeoIndex *) gix; + gix = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoIx), false); + + if(gix == NULL) { + return (GeoIndex *) gix; + } + /* try to allocate all the things we need */ - gix->pots = malloc(GEOPOTSTART*sizeof(GeoPot)); - gix->gc = malloc(GEOSLOTSTART*sizeof(GeoCoordinate)); + gix->pots = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, GEOPOTSTART*sizeof(GeoPot), false); + gix->gc = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, GEOSLOTSTART*sizeof(GeoCoordinate), false); /* if any of them fail, free the ones that succeeded */ /* and then return the NULL pointer for our user */ if ( ( gix->pots == NULL) || ( gix->gc == NULL) ) { - if ( gix->pots != NULL) free(gix->pots); - if ( gix->gc != NULL) free(gix->gc); - free(gix); + if ( gix->pots != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix->pots); + } + + if ( gix->gc != NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix->gc); + } + + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix); + return NULL; } @@ -561,9 +572,9 @@ void GeoIndex_free(GeoIndex * gi) } gix = (GeoIx *) gi; - free(gix->gc); - free(gix->pots); - free(gix); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix->gc); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix->pots); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gix); } /* =================================================== */ /* GeoMkHilbert routine */ @@ -795,16 +806,25 @@ GeoResults * GeoResultsCons(int alloc) return NULL; } - gres=malloc(sizeof(GeoResults)); - sa=malloc(alloc*sizeof(int)); - dd=malloc(alloc*sizeof(double)); + gres = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoResults), false); + sa = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, alloc*sizeof(int), false); + dd = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, alloc*sizeof(double), false); if( (gres==NULL) || (sa==NULL) || (dd==NULL) ) { - if(gres!=NULL) free(gres); - if(sa!=NULL) free(sa); - if(dd!=NULL) free(dd); + if(gres!=NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gres); + } + + if(sa!=NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, sa); + } + + if(dd!=NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, dd); + } + return NULL; } gres->pointsct = 0; @@ -951,22 +971,26 @@ GeoCoordinates * GeoAnswers (GeoIx * gix, GeoResults * gr) double mole; if (gr->pointsct == 0) { - free(gr->slot); - free(gr->snmd); - free(gr); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->slot); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->snmd); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr); return NULL; } - ans = malloc(sizeof(GeoCoordinates)); - gc = malloc(gr->pointsct * sizeof(GeoCoordinate)); + ans = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoCoordinates), false); + gc = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, gr->pointsct * sizeof(GeoCoordinate), false); if( (ans==NULL) || (gc==NULL) ) { - if(ans!=NULL) free(ans); - if(gc!=NULL) free(gc); - free(gr->slot); - free(gr->snmd); - free(gr); + if(ans!=NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, ans); + } + if(gc!=NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gc); + } + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->slot); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->snmd); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr); return NULL; } ans->length = gr->pointsct; @@ -989,8 +1013,10 @@ GeoCoordinates * GeoAnswers (GeoIx * gix, GeoResults * gr) j++; } ans->distances = gr->snmd; - free(gr->slot); - free(gr); + + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->slot); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr); + return ans; } /* =================================================== */ @@ -1095,9 +1121,9 @@ GeoCoordinates * GeoIndex_PointsWithinRadius(GeoIndex * gi, r = GeoResultsGrow(gres); if(r==-1) { - free(gres->snmd); - free(gres->slot); - free(gres); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gres->snmd); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gres->slot); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, gres); return NULL; } gres->slot[gres->pointsct]=slot; @@ -2060,9 +2086,9 @@ int GeoIndex_remove(GeoIndex * gi, GeoCoordinate * c) /* =================================================== */ void GeoIndex_CoordinatesFree(GeoCoordinates * clist) { - free(clist->coordinates); - free(clist->distances); - free(clist); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, clist->coordinates); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, clist->distances); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, clist); } /* =================================================== */ /* GeoIndex_hint does nothing! */ diff --git a/GeoIndex/GeoIndex.h b/GeoIndex/GeoIndex.h index 827eb0d353..a6ba99f3ce 100644 --- a/GeoIndex/GeoIndex.h +++ b/GeoIndex/GeoIndex.h @@ -28,14 +28,7 @@ /* GeoIndex.h - header file for GeoIndex algorithms */ /* Version 2.1 8.1.2012 R. A. Parker */ -#ifdef GEO_STANDALONE -#include -#include -#include -#include -#else #include "BasicsC/common.h" -#endif #ifdef __cplusplus extern "C" {