1
0
Fork 0

fixed value detection, added tests

This commit is contained in:
Jan Steemann 2012-05-02 14:34:24 +02:00
parent 475a1d61ee
commit a72bbaea08
16 changed files with 544 additions and 4199 deletions

View File

@ -26,6 +26,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "Ahuacatl/ahuacatl-ast-node.h"
#include "Ahuacatl/ahuacatl-collections.h"
#include "Ahuacatl/ahuacatl-functions.h"
#include "Ahuacatl/ahuacatl-parser-functions.h"
@ -411,6 +412,11 @@ TRI_aql_node_t* TRI_CreateNodeCollectionAql (TRI_aql_context_t* const context,
// duplicates are not a problem here, we simply ignore them
TRI_InsertKeyAssociativePointer(&context->_collectionNames, name, (void*) name, false);
if (context->_collectionNames._nrUsed > AQL_MAX_COLLECTIONS) {
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_TOO_MANY_COLLECTIONS, NULL);
return NULL;
}
return node;
}

View File

@ -973,6 +973,7 @@ TRI_aql_codegen_js_t* TRI_GenerateCodeAql (const void* const data) {
TRI_AppendStringStringBuffer(&generator->_buffer, "({ });");
LOG_DEBUG("generated code: %s", generator->_buffer._buffer);
//printf("generated code: %s", generator->_buffer._buffer);
return generator;
}

View File

@ -42,6 +42,25 @@
extern "C" {
#endif
// -----------------------------------------------------------------------------
// --SECTION-- defines
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief max number of collections usable in a query
////////////////////////////////////////////////////////////////////////////////
#define AQL_MAX_COLLECTIONS 32
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------

View File

@ -54,7 +54,7 @@ static TRI_string_buffer_t* FcallCode(const char* const name,
return NULL;
}
if (TRI_AppendStringStringBuffer(buffer, "(function(){return ") != TRI_ERROR_NO_ERROR) {
if (TRI_AppendStringStringBuffer(buffer, "(function(){return AHUACATL_FCALL(") != TRI_ERROR_NO_ERROR) {
TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer);
return NULL;
}
@ -64,7 +64,7 @@ static TRI_string_buffer_t* FcallCode(const char* const name,
return NULL;
}
if (TRI_AppendCharStringBuffer(buffer, '(') != TRI_ERROR_NO_ERROR) {
if (TRI_AppendStringStringBuffer(buffer, ",[") != TRI_ERROR_NO_ERROR) {
TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer);
return NULL;
}
@ -85,7 +85,7 @@ static TRI_string_buffer_t* FcallCode(const char* const name,
}
}
if (TRI_AppendStringStringBuffer(buffer, ");})") != TRI_ERROR_NO_ERROR) {
if (TRI_AppendStringStringBuffer(buffer, "]);})") != TRI_ERROR_NO_ERROR) {
TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer);
return NULL;
}
@ -143,6 +143,7 @@ static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context,
json = TRI_ExecuteResultContext(execContext);
if (!json) {
TRI_FreeExecutionContext(execContext);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_SCRIPT, NULL);
return NULL;
}
@ -166,8 +167,7 @@ static TRI_aql_node_t* OptimiseUnaryArithmeticOperation (TRI_aql_context_t* cons
}
if (!TRI_IsNumericValueNodeAql(operand)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE, NULL);
return node;
}
@ -202,8 +202,7 @@ static TRI_aql_node_t* OptimiseUnaryLogicalOperation (TRI_aql_context_t* const c
}
if (!TRI_IsBooleanValueNodeAql(operand)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE, NULL);
return node;
}
@ -240,14 +239,12 @@ static TRI_aql_node_t* OptimiseBinaryLogicalOperation (TRI_aql_context_t* const
isEligibleRhs = TRI_IsConstantValueNodeAql(rhs);
if (isEligibleLhs && !TRI_IsBooleanValueNodeAql(lhs)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE, NULL);
return node;
}
if (isEligibleRhs && !TRI_IsBooleanValueNodeAql(rhs)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE, NULL);
return node;
}
@ -304,20 +301,13 @@ static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* con
isEligibleRhs = TRI_IsConstantValueNodeAql(rhs);
if (isEligibleLhs && !TRI_IsNumericValueNodeAql(lhs)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE, NULL);
return node;
}
if (isEligibleRhs && !TRI_IsNumericValueNodeAql(rhs)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
return node;
}
if (TRI_IsConstantValueNodeAql(rhs) && !TRI_IsNumericValueNodeAql(rhs)) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE, NULL);
return node;
}
@ -342,16 +332,14 @@ static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* con
}
else if (node->_type == AQL_NODE_OPERATOR_BINARY_DIV) {
if (TRI_GetNumericNodeValueAql(rhs) == 0.0) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_DIVISON_BY_ZERO, NULL);
return node;
}
value = TRI_GetNumericNodeValueAql(lhs) / TRI_GetNumericNodeValueAql(rhs);
}
else if (node->_type == AQL_NODE_OPERATOR_BINARY_MOD) {
if (TRI_GetNumericNodeValueAql(rhs) == 0.0) {
// todo: fix error message
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_DIVISON_BY_ZERO, NULL);
return node;
}
value = fmod(TRI_GetNumericNodeValueAql(lhs), TRI_GetNumericNodeValueAql(rhs));

View File

@ -229,6 +229,10 @@ bool TRI_ValidateQueryContextAql (TRI_aql_context_t* const context) {
return false;
}
if (context->_error._code) {
return false;
}
// TRI_DumpTreeAql(context->_first);
return true;
}
@ -257,6 +261,10 @@ bool TRI_BindQueryContextAql (TRI_aql_context_t* const context,
// bind parameter injection failed
return false;
}
if (context->_error._code) {
return false;
}
return true;
}
@ -271,6 +279,10 @@ bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
// constant folding failed
return false;
}
if (context->_error._code) {
return false;
}
// TRI_DumpTreeAql((TRI_aql_node_t*) context->_first);
return true;
@ -295,6 +307,10 @@ bool TRI_LockQueryContextAql (TRI_aql_context_t* const context) {
if (!TRI_AddBarrierCollectionsAql(context)) {
return false;
}
if (context->_error._code) {
return false;
}
return true;
}

View File

@ -40,8 +40,8 @@
/// @brief shorthand to register a query function and process the result
////////////////////////////////////////////////////////////////////////////////
#define REGISTER_FUNCTION(internalName, externalName, deterministic, minArgs, maxArgs) \
result &= TRI_RegisterFunctionAql (functions, internalName, "AHUACATL_" externalName, deterministic, minArgs, maxArgs);
#define REGISTER_FUNCTION(internalName, externalName, deterministic, group, minArgs, maxArgs) \
result &= TRI_RegisterFunctionAql (functions, internalName, "AHUACATL_" externalName, deterministic, group, minArgs, maxArgs);
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -114,30 +114,37 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) {
NULL);
// cast functions
REGISTER_FUNCTION("TONUMBER", "CAST_NUMBER", true, 1, 1);
REGISTER_FUNCTION("TOSTRING", "CAST_STRING", true, 1, 1);
REGISTER_FUNCTION("TOBOOL", "CAST_BOOL", true, 1, 1);
REGISTER_FUNCTION("TONULL", "CAST_NULL", true, 1, 1);
REGISTER_FUNCTION("TONUMBER", "CAST_NUMBER", true, false, 1, 1);
REGISTER_FUNCTION("TOSTRING", "CAST_STRING", true, false, 1, 1);
REGISTER_FUNCTION("TOBOOL", "CAST_BOOL", true, false, 1, 1);
REGISTER_FUNCTION("TONULL", "CAST_NULL", true, false, 1, 1);
// string concat
REGISTER_FUNCTION("CONCAT", "STRING_CONCAT", true, false, 2, 256);
// type check functions
REGISTER_FUNCTION("ISNULL", "IS_NULL", true, 1, 1);
REGISTER_FUNCTION("ISBOOL", "IS_BOOL", true, 1, 1);
REGISTER_FUNCTION("ISNUMBER", "IS_NUMBER", true, 1, 1);
REGISTER_FUNCTION("ISSTRING", "IS_STRING", true, 1, 1);
REGISTER_FUNCTION("ISLIST", "IS_LIST", true, 1, 1);
REGISTER_FUNCTION("ISDOCUMENT", "IS_DOCUMENT", true, 1, 1);
// string concat
REGISTER_FUNCTION("CONCAT", "STRING_CONCAT", true, 2, 256);
// numeric functions
REGISTER_FUNCTION("ISNULL", "IS_NULL", true, false, 1, 1);
REGISTER_FUNCTION("ISBOOL", "IS_BOOL", true, false, 1, 1);
REGISTER_FUNCTION("ISNUMBER", "IS_NUMBER", true, false, 1, 1);
REGISTER_FUNCTION("ISSTRING", "IS_STRING", true, false, 1, 1);
REGISTER_FUNCTION("ISLIST", "IS_LIST", true, false, 1, 1);
REGISTER_FUNCTION("ISDOCUMENT", "IS_DOCUMENT", true, false, 1, 1);
// numeric functions
REGISTER_FUNCTION("FLOOR", "NUMBER_FLOOR", true, false, 1, 1);
REGISTER_FUNCTION("CEIL", "NUMBER_CEIL", true, false, 1, 1);
REGISTER_FUNCTION("ROUND", "NUMBER_ROUND", true, false, 1, 1);
REGISTER_FUNCTION("ABS", "NUMBER_ABS", true, false, 1, 1);
REGISTER_FUNCTION("RAND", "NUMBER_RAND", false, false, 0, 0);
// string functions
// misc functions
REGISTER_FUNCTION("MERGE", "MERGE", true, 2, 256);
REGISTER_FUNCTION("UNION", "UNION", true, 2, 256);
REGISTER_FUNCTION("LENGTH", "LENGTH", true, 1, 1);
REGISTER_FUNCTION("MERGE", "MERGE", true, false, 2, 256);
REGISTER_FUNCTION("UNION", "UNION", true, false, 2, 256);
REGISTER_FUNCTION("LENGTH", "LENGTH", true, true, 1, 1);
REGISTER_FUNCTION("MIN", "MIN", true, true, 1, 256);
REGISTER_FUNCTION("MAX", "MAX", true, true, 1, 256);
if (!result) {
TRI_FreeFunctionsAql(functions);
@ -212,6 +219,7 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
const char* const externalName,
const char* const internalName,
const bool isDeterministic,
const bool isGroup,
const int minArgs,
const int maxArgs) {
TRI_aql_function_t* function;
@ -236,9 +244,10 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
return false;
}
function->_isDeterministic = isDeterministic;
function->_isGroup = isGroup;
function->_minArgs = minArgs;
function->_maxArgs = maxArgs;
function->_isDeterministic = isDeterministic;
if (TRI_InsertKeyAssociativePointer(functions, externalName, function, false)) {
// function already registered

View File

@ -52,6 +52,7 @@ typedef struct TRI_aql_function_s {
int _minArgs;
int _maxArgs;
bool _isDeterministic;
bool _isGroup;
}
TRI_aql_function_t;
@ -94,6 +95,7 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t*,
const char* const,
const char* const,
const bool,
const bool,
const int,
const int);

View File

@ -123,6 +123,11 @@ ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED,1523,"document attribute '%s' is assig
ERROR_QUERY_VARIABLE_NAME_INVALID,1524,"variable name '%s' has an invalid format","Will be raised when an invalid variable name is used."
ERROR_QUERY_BIND_PARAMETERS_INVALID,1525,"invalid structure of bind parameters","Will be raised when the structure of bind parameters passed has an unexpected format."
ERROR_QUERY_COLLECTION_LOCK_FAILED,1526,"unable to read-lock collection %s","Will be raised when a read lock on the collection cannot be acquired."
ERROR_QUERY_TOO_MANY_COLLECTIONS,1527,"too many collections","Will be raised when the number of collections in a query is beyond the allowed value."
ERROR_QUERY_INVALID_LOGICAL_VALUE,1528,"invalid logical value","Will be raised when a non-boolean value is used in a logical operation."
ERROR_QUERY_INVALID_ARITHMETIC_VALUE,1529,"invalid arithmetic value","Will be raised when a non-numeric value is used in an arithmetic operation."
ERROR_QUERY_DIVISON_BY_ZERO,1530,"division by zero","Will be raised when there is an attempt to divide by zero."
ERROR_QUERY_SCRIPT,1531,"runtime error","Will be raised when a runtime error is caused by the query."
################################################################################
## AvocadoDB cursor errors

View File

@ -89,6 +89,11 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_QUERY_VARIABLE_NAME_INVALID, "variable name '%s' has an invalid format");
REG_ERROR(ERROR_QUERY_BIND_PARAMETERS_INVALID, "invalid structure of bind parameters");
REG_ERROR(ERROR_QUERY_COLLECTION_LOCK_FAILED, "unable to read-lock collection %s");
REG_ERROR(ERROR_QUERY_TOO_MANY_COLLECTIONS, "too many collections");
REG_ERROR(ERROR_QUERY_INVALID_LOGICAL_VALUE, "invalid logical value");
REG_ERROR(ERROR_QUERY_INVALID_ARITHMETIC_VALUE, "invalid arithmetic value");
REG_ERROR(ERROR_QUERY_DIVISON_BY_ZERO, "division by zero");
REG_ERROR(ERROR_QUERY_SCRIPT, "runtime error");
REG_ERROR(ERROR_CURSOR_NOT_FOUND, "cursor not found");
REG_ERROR(ERROR_SESSION_USERHANDLER_URL_INVALID, "expecting <prefix>/user/<username>");
REG_ERROR(ERROR_SESSION_USERHANDLER_CANNOT_CREATE_USER, "cannot create user");

View File

@ -195,6 +195,18 @@ extern "C" {
/// unexpected format.
/// - 1526: @CODE{unable to read-lock collection \%s}
/// Will be raised when a read lock on the collection cannot be acquired.
/// - 1527: @CODE{too many collections}
/// Will be raised when the number of collections in a query is beyond the
/// allowed value.
/// - 1528: @CODE{invalid logical value}
/// Will be raised when a non-boolean value is used in a logical operation.
/// - 1529: @CODE{invalid arithmetic value}
/// Will be raised when a non-numeric value is used in an arithmetic
/// operation.
/// - 1530: @CODE{division by zero}
/// Will be raised when there is an attempt to divide by zero.
/// - 1531: @CODE{runtime error}
/// Will be raised when a runtime error is caused by the query.
/// - 1600: @CODE{cursor not found}
/// Will be raised when a cursor is requested via its id but a cursor with
/// that id cannot be found.
@ -1099,6 +1111,57 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_QUERY_COLLECTION_LOCK_FAILED (1526)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1527: ERROR_QUERY_TOO_MANY_COLLECTIONS
///
/// too many collections
///
/// Will be raised when the number of collections in a query is beyond the
/// allowed value.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_TOO_MANY_COLLECTIONS (1527)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1528: ERROR_QUERY_INVALID_LOGICAL_VALUE
///
/// invalid logical value
///
/// Will be raised when a non-boolean value is used in a logical operation.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE (1528)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1529: ERROR_QUERY_INVALID_ARITHMETIC_VALUE
///
/// invalid arithmetic value
///
/// Will be raised when a non-numeric value is used in an arithmetic operation.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE (1529)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1530: ERROR_QUERY_DIVISON_BY_ZERO
///
/// division by zero
///
/// Will be raised when there is an attempt to divide by zero.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_DIVISON_BY_ZERO (1530)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1531: ERROR_QUERY_SCRIPT
///
/// runtime error
///
/// Will be raised when a runtime error is caused by the query.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_SCRIPT (1531)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1600: ERROR_CURSOR_NOT_FOUND
///

View File

@ -83,6 +83,11 @@ ModuleCache["/internal"].exports.errors = {
"ERROR_QUERY_VARIABLE_NAME_INVALID" : { "code" : 1524, "message" : "variable name '%s' has an invalid format" },
"ERROR_QUERY_BIND_PARAMETERS_INVALID" : { "code" : 1525, "message" : "invalid structure of bind parameters" },
"ERROR_QUERY_COLLECTION_LOCK_FAILED" : { "code" : 1526, "message" : "unable to read-lock collection %s" },
"ERROR_QUERY_TOO_MANY_COLLECTIONS" : { "code" : 1527, "message" : "too many collections" },
"ERROR_QUERY_INVALID_LOGICAL_VALUE" : { "code" : 1528, "message" : "invalid logical value" },
"ERROR_QUERY_INVALID_ARITHMETIC_VALUE" : { "code" : 1529, "message" : "invalid arithmetic value" },
"ERROR_QUERY_DIVISON_BY_ZERO" : { "code" : 1530, "message" : "division by zero" },
"ERROR_QUERY_SCRIPT" : { "code" : 1531, "message" : "runtime error" },
"ERROR_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" },
"ERROR_SESSION_USERHANDLER_URL_INVALID" : { "code" : 1700, "message" : "expecting <prefix>/user/<username>" },
"ERROR_SESSION_USERHANDLER_CANNOT_CREATE_USER" : { "code" : 1701, "message" : "cannot create user" },

View File

@ -84,6 +84,11 @@ static string JS_common_bootstrap_errors =
" \"ERROR_QUERY_VARIABLE_NAME_INVALID\" : { \"code\" : 1524, \"message\" : \"variable name '%s' has an invalid format\" }, \n"
" \"ERROR_QUERY_BIND_PARAMETERS_INVALID\" : { \"code\" : 1525, \"message\" : \"invalid structure of bind parameters\" }, \n"
" \"ERROR_QUERY_COLLECTION_LOCK_FAILED\" : { \"code\" : 1526, \"message\" : \"unable to read-lock collection %s\" }, \n"
" \"ERROR_QUERY_TOO_MANY_COLLECTIONS\" : { \"code\" : 1527, \"message\" : \"too many collections\" }, \n"
" \"ERROR_QUERY_INVALID_LOGICAL_VALUE\" : { \"code\" : 1528, \"message\" : \"invalid logical value\" }, \n"
" \"ERROR_QUERY_INVALID_ARITHMETIC_VALUE\" : { \"code\" : 1529, \"message\" : \"invalid arithmetic value\" }, \n"
" \"ERROR_QUERY_DIVISON_BY_ZERO\" : { \"code\" : 1530, \"message\" : \"division by zero\" }, \n"
" \"ERROR_QUERY_SCRIPT\" : { \"code\" : 1531, \"message\" : \"runtime error\" }, \n"
" \"ERROR_CURSOR_NOT_FOUND\" : { \"code\" : 1600, \"message\" : \"cursor not found\" }, \n"
" \"ERROR_SESSION_USERHANDLER_URL_INVALID\" : { \"code\" : 1700, \"message\" : \"expecting <prefix>/user/<username>\" }, \n"
" \"ERROR_SESSION_USERHANDLER_CANNOT_CREATE_USER\" : { \"code\" : 1701, \"message\" : \"cannot create user\" }, \n"

View File

@ -86,14 +86,6 @@ function AHUACATL_FCALL(name, parameters) {
return name.apply(null, parameters);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the value of a bind parameter
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_PARAMETER (name) {
throw "bind parameters not yet supported";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the numeric value or undefined if it is out of range
////////////////////////////////////////////////////////////////////////////////
@ -1131,6 +1123,75 @@ function AHUACATL_IS_DOCUMENT (value) {
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- numeric functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief integer closest to value, not greater than value
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_NUMBER_FLOOR (value) {
if (!AHUACATL_IS_NUMBER(value)) {
throw "expecting number for floor";
}
return Math.floor(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief integer closest to value and not less than value
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_NUMBER_CEIL (value) {
if (!AHUACATL_IS_NUMBER(value)) {
throw "expecting number for ceil";
}
return Math.ceil(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief integer closest to value
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_NUMBER_ROUND (value) {
if (!AHUACATL_IS_NUMBER(value)) {
throw "expecting number for round";
}
return Math.round(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief absolute value
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_NUMBER_ABS (value) {
if (!AHUACATL_IS_NUMBER(value)) {
throw "expecting number for abs";
}
return Math.abs(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief a random value between 0 and 1
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_NUMBER_RAND () {
return Math.random();
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- high level query functions
// -----------------------------------------------------------------------------
@ -1280,6 +1341,56 @@ function AHUACATL_UNION () {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief maximum of all values
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_MAX () {
var result = null;
var value = arguments[0];
AHUACATL_LIST(value);
for (var i in value) {
var currentValue = value[i];
if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {
continue;
}
if (result === null || AHUACATL_RELATIONAL_GREATER(currentValue, result)) {
result = currentValue;
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief minimum of all values
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_MIN () {
var result = null;
var value = arguments[0];
AHUACATL_LIST(value);
for (var i in value) {
var currentValue = value[i];
if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {
continue;
}
if (result === null || AHUACATL_RELATIONAL_LESS(currentValue, result)) {
result = currentValue;
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -88,14 +88,6 @@ static string JS_server_ahuacatl =
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief get the value of a bind parameter\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_PARAMETER (name) {\n"
" throw \"bind parameters not yet supported\";\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief return the numeric value or undefined if it is out of range\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
@ -1133,6 +1125,75 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- numeric functions\n"
"// -----------------------------------------------------------------------------\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @addtogroup Ahuacatl\n"
"/// @{\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief integer closest to value, not greater than value\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_NUMBER_FLOOR (value) {\n"
" if (!AHUACATL_IS_NUMBER(value)) {\n"
" throw \"expecting number for floor\";\n"
" }\n"
" \n"
" return Math.floor(value);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief integer closest to value and not less than value\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_NUMBER_CEIL (value) {\n"
" if (!AHUACATL_IS_NUMBER(value)) {\n"
" throw \"expecting number for ceil\";\n"
" }\n"
" \n"
" return Math.ceil(value);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief integer closest to value \n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_NUMBER_ROUND (value) {\n"
" if (!AHUACATL_IS_NUMBER(value)) {\n"
" throw \"expecting number for round\";\n"
" }\n"
" \n"
" return Math.round(value);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief absolute value\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_NUMBER_ABS (value) {\n"
" if (!AHUACATL_IS_NUMBER(value)) {\n"
" throw \"expecting number for abs\";\n"
" }\n"
" \n"
" return Math.abs(value);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief a random value between 0 and 1\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_NUMBER_RAND () {\n"
" return Math.random();\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @}\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- high level query functions\n"
"// -----------------------------------------------------------------------------\n"
"\n"
@ -1282,6 +1343,56 @@ static string JS_server_ahuacatl =
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief maximum of all values\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_MAX () {\n"
" var result = null;\n"
" var value = arguments[0];\n"
"\n"
" AHUACATL_LIST(value);\n"
"\n"
" for (var i in value) {\n"
" var currentValue = value[i];\n"
" \n"
" if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {\n"
" continue;\n"
" }\n"
"\n"
" if (result === null || AHUACATL_RELATIONAL_GREATER(currentValue, result)) {\n"
" result = currentValue;\n"
" }\n"
" }\n"
"\n"
" return result;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief minimum of all values\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_MIN () {\n"
" var result = null;\n"
" var value = arguments[0];\n"
"\n"
" AHUACATL_LIST(value);\n"
"\n"
" for (var i in value) {\n"
" var currentValue = value[i];\n"
" \n"
" if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {\n"
" continue;\n"
" }\n"
" \n"
" if (result === null || AHUACATL_RELATIONAL_LESS(currentValue, result)) {\n"
" result = currentValue;\n"
" }\n"
" }\n"
"\n"
" return result;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @}\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"

View File

@ -106,7 +106,17 @@ function ahuacatlFunctionsTestSuite () {
/// @brief test length function
////////////////////////////////////////////////////////////////////////////////
testLength : function () {
testLength1 : function () {
var expected = [ 0, 0, 0 ];
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] LET quarters = ((FOR q IN [ ] return q)) return LENGTH(quarters)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test length function
////////////////////////////////////////////////////////////////////////////////
testLength2 : function () {
var expected = [ 4, 4, 4 ];
var actual = getQueryResults("FOR year IN [ 2010, 2011, 2012 ] LET quarters = ((FOR q IN [ 1, 2, 3, 4 ] return q)) return LENGTH(quarters)", true);
assertEqual(expected, actual);
@ -116,12 +126,77 @@ function ahuacatlFunctionsTestSuite () {
/// @brief test concat function
////////////////////////////////////////////////////////////////////////////////
testConcat : function () {
testConcat1 : function () {
var expected = [ "theQuickBrownFoxJumps" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT('the', 'Quick', null, 'Brown', null, 'Fox', 'Jumps')", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test concat function
////////////////////////////////////////////////////////////////////////////////
testConcat2 : function () {
var expected = [ "theQuickBrownアボカドJumps名称について" ];
var actual = getQueryResults("FOR r IN [ 1 ] return CONCAT('the', 'Quick', null, 'Brown', null, 'アボカド', 'Jumps', '名称について')", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test floor function
////////////////////////////////////////////////////////////////////////////////
testFloor : function () {
var expected = [ -100, -3, -3, -3, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 99 ];
var actual = getQueryResults("FOR r IN [ -99.999, -3, -2.1, -2.01, -2, -1.99, -1.1, -1.01, -1, -0.9, -0.6, -0.5, -0.4, -0.1, -0.01, 0, 0.01, 0.1, 0.4, 0.5, 0.6, 0.9, 1, 1.01, 1.1, 1.99, 2, 2.01, 2.1, 3, 99.999 ] return FLOOR(r)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test ceil function
////////////////////////////////////////////////////////////////////////////////
testCeil : function () {
var expected = [ -99, -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 100 ];
var actual = getQueryResults("FOR r IN [ -99.999, -3, -2.1, -2.01, -2, -1.99, -1.1, -1.01, -1, -0.9, -0.6, -0.5, -0.4, -0.1, -0.01, 0, 0.01, 0.1, 0.4, 0.5, 0.6, 0.9, 1, 1.01, 1.1, 1.99, 2, 2.01, 2.1, 3, 99.999 ] return CEIL(r)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test abs function
////////////////////////////////////////////////////////////////////////////////
testAbs : function () {
var expected = [ 99.999, 3, 2.1, 2.01, 2, 1.99, 1.1, 1.01, 1, 0.9, 0.6, 0.5, 0.4, 0.1, 0.01, 0, 0.01, 0.1, 0.4, 0.5, 0.6, 0.9, 1, 1.01, 1.1, 1.99, 2, 2.01, 2.1, 3, 99.999 ];
var actual = getQueryResults("FOR r IN [ -99.999, -3, -2.1, -2.01, -2, -1.99, -1.1, -1.01, -1, -0.9, -0.6, -0.5, -0.4, -0.1, -0.01, 0, 0.01, 0.1, 0.4, 0.5, 0.6, 0.9, 1, 1.01, 1.1, 1.99, 2, 2.01, 2.1, 3, 99.999 ] return ABS(r)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test round function
////////////////////////////////////////////////////////////////////////////////
testRound : function () {
var expected = [ -100, -3, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 100 ];
var actual = getQueryResults("FOR r IN [ -99.999, -3, -2.1, -2.01, -2, -1.99, -1.1, -1.01, -1, -0.9, -0.6, -0.5, -0.4, -0.1, -0.01, 0, 0.01, 0.1, 0.4, 0.5, 0.6, 0.9, 1, 1.01, 1.1, 1.99, 2, 2.01, 2.1, 3, 99.999 ] return ROUND(r)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test rand function
////////////////////////////////////////////////////////////////////////////////
testRand : function () {
var actual = getQueryResults("FOR r IN [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ] return RAND()", true);
for (var i in actual) {
if (!actual.hasOwnProperty(i)) {
continue;
}
var value = actual[i];
assertTrue(value >= 0.0 && value < 1.0);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test merge function
////////////////////////////////////////////////////////////////////////////////
@ -192,6 +267,65 @@ function ahuacatlFunctionsTestSuite () {
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min function
////////////////////////////////////////////////////////////////////////////////
testMin1 : function () {
var expected = [ null, null ];
var actual = getQueryResults("FOR u IN [ [ ], [ null, null ] ] return MIN(u)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min function
////////////////////////////////////////////////////////////////////////////////
testMin2 : function () {
var expected = [ 1, 1, 1, 1, 1, 1 ];
var actual = getQueryResults("FOR u IN [ [ 1, 2, 3 ], [ 3, 2, 1 ], [ 1, 3, 2 ], [ 2, 3, 1 ], [ 2, 1, 3 ], [ 3, 1, 2 ] ] return MIN(u)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min function
////////////////////////////////////////////////////////////////////////////////
testMin3 : function () {
var expected = [ 2, false, false, false, false, true, -1, '', 1 ];
var actual = getQueryResults("FOR u IN [ [ 3, 2, '1' ], [ [ ], null, true, false, 1, '0' ], [ '0', 1, false, true, null, [ ] ], [ false, true ], [ 0, false ], [ true, 0 ], [ '0', -1 ], [ '', '-1' ], [ [ ], 1 ] ] return MIN(u)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test max function
////////////////////////////////////////////////////////////////////////////////
testMax1 : function () {
var expected = [ null, null ];
var actual = getQueryResults("FOR u IN [ [ ], [ null, null ] ] return MAX(u)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test max function
////////////////////////////////////////////////////////////////////////////////
testMax2 : function () {
var expected = [ 3, 3, 3, 3, 3, 3 ];
var actual = getQueryResults("FOR u IN [ [ 1, 2, 3 ], [ 3, 2, 1 ], [ 1, 3, 2 ], [ 2, 3, 1 ], [ 2, 1, 3 ], [ 3, 1, 2 ] ] return MAX(u)", true);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test min function
////////////////////////////////////////////////////////////////////////////////
testMax3 : function () {
var expected = [ '1', [ ], [ ], true, 0, 0, '0', '-1', [ ] ];
var actual = getQueryResults("FOR u IN [ [ 3, 2, '1' ], [ [ ], null, true, false, 1, '0' ], [ '0', 1, false, true, null, [ ] ], [ false, true ], [ 0, false ], [ true, 0 ], [ '0', -1 ], [ '', '-1' ], [ [ ], 1 ] ] return MAX(u)", true);
assertEqual(expected, actual);
},
};
}

File diff suppressed because it is too large Load Diff