mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
71bf83be1b
|
@ -222,7 +222,7 @@ A Foxx Model can be initialized with an object of attributes and their values.
|
|||
The attributes property is the internal hash containing the model's state.
|
||||
|
||||
#### Foxx.Model#toJSON
|
||||
@copydetails jsf_foxx_model_toJSON
|
||||
@copydetails JSF_foxx_model_toJSON
|
||||
|
||||
## Foxx.Repository
|
||||
|
||||
|
|
|
@ -210,6 +210,7 @@ endif
|
|||
################################################################################
|
||||
|
||||
SHELL_COMMON = @top_srcdir@/js/common/tests/shell-require.js \
|
||||
@top_srcdir@/js/common/tests/shell-aqlfunctions.js \
|
||||
@top_srcdir@/js/common/tests/shell-attributes.js \
|
||||
@top_srcdir@/js/common/tests/shell-collection.js \
|
||||
@top_srcdir@/js/common/tests/shell-collection-volatile.js \
|
||||
|
|
|
@ -100,6 +100,64 @@ inline static void InitNode (TRI_aql_context_t* const context,
|
|||
TRI_RegisterNodeContextAql(context, node);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST function call node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* CreateNodeInternalFcall (TRI_aql_context_t* const context,
|
||||
const char* const name,
|
||||
const char* const internalName,
|
||||
const TRI_aql_node_t* const parameters) {
|
||||
CREATE_NODE(TRI_AQL_NODE_FCALL)
|
||||
|
||||
TRI_AQL_NODE_DATA(node) = 0;
|
||||
|
||||
{
|
||||
TRI_aql_function_t* function;
|
||||
TRI_associative_pointer_t* functions;
|
||||
|
||||
assert(context->_vocbase);
|
||||
functions = context->_vocbase->_functions;
|
||||
assert(functions);
|
||||
|
||||
function = TRI_GetByExternalNameFunctionAql(functions, internalName);
|
||||
|
||||
if (function == NULL) {
|
||||
// function name is unknown
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_FUNCTION_NAME_UNKNOWN, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// validate function call arguments
|
||||
if (! TRI_ValidateArgsFunctionAql(context, function, parameters)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialise
|
||||
ADD_MEMBER(parameters)
|
||||
TRI_AQL_NODE_DATA(node) = function;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST function call node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_aql_node_t* CreateNodeUserFcall (TRI_aql_context_t* const context,
|
||||
const char* const name,
|
||||
char* const internalName,
|
||||
const TRI_aql_node_t* const parameters) {
|
||||
CREATE_NODE(TRI_AQL_NODE_FCALL_USER)
|
||||
|
||||
// we'll take ownership of the function name now
|
||||
TRI_AQL_NODE_STRING(node) = internalName;
|
||||
ADD_MEMBER(parameters)
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -934,38 +992,33 @@ TRI_aql_node_t* TRI_CreateNodeArrayElementAql (TRI_aql_context_t* const context,
|
|||
TRI_aql_node_t* TRI_CreateNodeFcallAql (TRI_aql_context_t* const context,
|
||||
const char* const name,
|
||||
const TRI_aql_node_t* const parameters) {
|
||||
CREATE_NODE(TRI_AQL_NODE_FCALL)
|
||||
|
||||
// initialise
|
||||
TRI_AQL_NODE_DATA(node) = NULL;
|
||||
TRI_aql_node_t* node;
|
||||
char* upperName;
|
||||
|
||||
if (name == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
{
|
||||
TRI_aql_function_t* function;
|
||||
TRI_associative_pointer_t* functions;
|
||||
if (strchr(name, TRI_AQL_NAMESPACE_SEPARATOR_CHAR) != NULL) {
|
||||
upperName = TRI_UpperAsciiStringZ(TRI_CORE_MEM_ZONE, name);
|
||||
}
|
||||
else {
|
||||
upperName = TRI_Concatenate2String(TRI_AQL_DEFAULT_PREFIX, TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, name));
|
||||
}
|
||||
|
||||
assert(context->_vocbase);
|
||||
functions = context->_vocbase->_functions;
|
||||
assert(functions);
|
||||
|
||||
function = TRI_GetByExternalNameFunctionAql(functions, name);
|
||||
|
||||
if (! function) {
|
||||
// function name is unknown
|
||||
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_FUNCTION_NAME_UNKNOWN, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// validate function call arguments
|
||||
if (! TRI_ValidateArgsFunctionAql(context, function, parameters)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADD_MEMBER(parameters)
|
||||
TRI_AQL_NODE_DATA(node) = function;
|
||||
if (upperName == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (*upperName == '_') {
|
||||
// default internal namespace
|
||||
node = CreateNodeInternalFcall(context, name, upperName, parameters);
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, upperName);
|
||||
}
|
||||
else {
|
||||
// user namespace
|
||||
node = CreateNodeUserFcall(context, name, upperName, parameters);
|
||||
// upperName intentionally not freed!
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
|
@ -1427,7 +1427,8 @@ static void ProcessArgList (TRI_aql_codegen_js_t* const generator,
|
|||
ScopeOutput(generator, ", ");
|
||||
}
|
||||
|
||||
if (parameter->_type == TRI_AQL_NODE_COLLECTION &&
|
||||
if (function != NULL &&
|
||||
parameter->_type == TRI_AQL_NODE_COLLECTION &&
|
||||
TRI_ConvertParameterFunctionAql(function, i)) {
|
||||
// collection arguments will be created as string argument => e.g. "users"
|
||||
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(parameter, 0);
|
||||
|
@ -1880,8 +1881,8 @@ static void ProcessSubquery (TRI_aql_codegen_js_t* const generator,
|
|||
/// @brief generate code for function calls
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ProcessFcall (TRI_aql_codegen_js_t* const generator,
|
||||
const TRI_aql_node_t* const node) {
|
||||
static void ProcessFcallInternal (TRI_aql_codegen_js_t* const generator,
|
||||
const TRI_aql_node_t* const node) {
|
||||
ScopeOutput(generator, "aql.");
|
||||
ScopeOutput(generator, TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node)));
|
||||
ScopeOutput(generator, "(");
|
||||
|
@ -1889,6 +1890,19 @@ static void ProcessFcall (TRI_aql_codegen_js_t* const generator,
|
|||
ScopeOutput(generator, ")");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate code for function calls
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ProcessFcallUser (TRI_aql_codegen_js_t* const generator,
|
||||
const TRI_aql_node_t* const node) {
|
||||
ScopeOutput(generator, "aql.FCALL_USER(");
|
||||
ScopeOutputQuoted(generator, TRI_AQL_NODE_STRING(node));
|
||||
ScopeOutput(generator, ", [");
|
||||
ProcessArgList(generator, NULL, TRI_AQL_NODE_MEMBER(node, 0));
|
||||
ScopeOutput(generator, "])");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate code for a scope start
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2402,7 +2416,10 @@ static void ProcessNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_no
|
|||
ProcessTernary(generator, node);
|
||||
break;
|
||||
case TRI_AQL_NODE_FCALL:
|
||||
ProcessFcall(generator, node);
|
||||
ProcessFcallInternal(generator, node);
|
||||
break;
|
||||
case TRI_AQL_NODE_FCALL_USER:
|
||||
ProcessFcallUser(generator, node);
|
||||
break;
|
||||
case TRI_AQL_NODE_FOR:
|
||||
ProcessFor(generator, node);
|
||||
|
|
|
@ -423,7 +423,57 @@ char* TRI_RegisterStringAql (TRI_aql_context_t* const context,
|
|||
ABORT_OOM
|
||||
}
|
||||
|
||||
TRI_PushBackVectorPointer(&context->_memory._strings, copy);
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString2Aql (TRI_aql_context_t* const context,
|
||||
const char* const s1,
|
||||
const char* const s2) {
|
||||
char* copy;
|
||||
|
||||
copy = TRI_Concatenate2StringZ(TRI_UNKNOWN_MEM_ZONE, s1, s2);
|
||||
|
||||
if (copy == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString3Aql (TRI_aql_context_t* const context,
|
||||
const char* const s1,
|
||||
const char* const s2,
|
||||
const char* const s3) {
|
||||
char* copy;
|
||||
|
||||
copy = TRI_Concatenate3StringZ(TRI_UNKNOWN_MEM_ZONE, s1, s2, s3);
|
||||
|
||||
if (copy == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
|
|
@ -143,6 +143,23 @@ char* TRI_RegisterStringAql (TRI_aql_context_t* const,
|
|||
const size_t,
|
||||
const bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString2Aql (TRI_aql_context_t* const,
|
||||
const char* const,
|
||||
const char* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString3Aql (TRI_aql_context_t* const,
|
||||
const char* const,
|
||||
const char* const,
|
||||
const char* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -603,6 +603,22 @@ bool TRI_NodeStringAql (TRI_string_buffer_t* const buffer,
|
|||
return TRI_AppendStringStringBuffer(buffer, ")") == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
case TRI_AQL_NODE_FCALL_USER: {
|
||||
if (TRI_AppendStringStringBuffer(buffer, TRI_AQL_NODE_STRING(node)) != TRI_ERROR_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TRI_AppendStringStringBuffer(buffer, "(") != TRI_ERROR_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return TRI_AppendStringStringBuffer(buffer, ")") == TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
case TRI_AQL_NODE_EXPAND: {
|
||||
return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 3));
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define REGISTER_FUNCTION(internalName, externalName, deterministic, group, argPattern, optimiseCallback) \
|
||||
result &= TRI_RegisterFunctionAql(functions, internalName, externalName, deterministic, group, argPattern, optimiseCallback)
|
||||
result &= TRI_RegisterFunctionAql(functions, TRI_AQL_DEFAULT_PREFIX internalName, externalName, deterministic, group, argPattern, optimiseCallback)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shorthand to check an argument and return an error if it is invalid
|
||||
|
@ -680,10 +680,11 @@ void TRI_FreeFunctionsAql (TRI_associative_pointer_t* functions) {
|
|||
|
||||
for (i = 0; i < functions->_nrAlloc; ++i) {
|
||||
TRI_aql_function_t* function = (TRI_aql_function_t*) functions->_table[i];
|
||||
if (!function) {
|
||||
if (function == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_argPattern);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
|
||||
|
@ -707,13 +708,14 @@ TRI_aql_function_t* TRI_GetByExternalNameFunctionAql (TRI_associative_pointer_t*
|
|||
|
||||
// normalize the name by upper-casing it
|
||||
upperName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, externalName);
|
||||
|
||||
if (upperName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, (void*) upperName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, upperName);
|
||||
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
|
@ -744,21 +746,30 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
|
|||
return false;
|
||||
}
|
||||
|
||||
function->_externalName = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, externalName);
|
||||
function->_externalName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, externalName);
|
||||
if (function->_externalName == NULL) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
|
||||
return false;
|
||||
}
|
||||
|
||||
// normalize name by upper-casing it
|
||||
function->_internalName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, internalName);
|
||||
function->_internalName = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, internalName);
|
||||
if (function->_internalName == NULL) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
|
||||
return false;
|
||||
}
|
||||
|
||||
function->_argPattern = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, argPattern);
|
||||
if (function->_argPattern == NULL) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (TRI_InsertKeyAssociativePointer(functions, externalName, function, false)) {
|
||||
if (TRI_InsertKeyAssociativePointer(functions, function->_externalName, function, false)) {
|
||||
// function already registered
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName);
|
||||
|
@ -768,7 +779,6 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
|
|||
|
||||
function->_isDeterministic = isDeterministic;
|
||||
function->_isGroup = isGroup;
|
||||
function->_argPattern = argPattern;
|
||||
function->optimise = optimise;
|
||||
|
||||
// set minArgs and maxArgs
|
||||
|
|
|
@ -36,10 +36,55 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct TRI_aql_context_s;
|
||||
struct TRI_aql_field_access_s;
|
||||
struct TRI_associative_pointer_s;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public defines
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default namespace for aql functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_AQL_DEFAULT_NAMESPACE "_AQL"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief separator between namespace and function name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_AQL_NAMESPACE_SEPARATOR ":"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief separator between namespace and function name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_AQL_NAMESPACE_SEPARATOR_CHAR ':'
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default namespace for aql functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_AQL_DEFAULT_PREFIX TRI_AQL_DEFAULT_NAMESPACE TRI_AQL_NAMESPACE_SEPARATOR
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
|
@ -54,13 +99,26 @@ typedef struct TRI_aql_function_s {
|
|||
char* _internalName;
|
||||
bool _isDeterministic;
|
||||
bool _isGroup;
|
||||
const char* _argPattern;
|
||||
char* _argPattern;
|
||||
size_t _minArgs;
|
||||
size_t _maxArgs;
|
||||
void (*optimise)(const TRI_aql_node_t* const, struct TRI_aql_context_s* const, struct TRI_aql_field_access_s*);
|
||||
}
|
||||
TRI_aql_function_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialise the array with the function declarations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,10 @@
|
|||
/* A Bison parser, made by GNU Bison 2.5. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
/* A Bison parser, made by GNU Bison 2.4.1. */
|
||||
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -96,7 +98,7 @@
|
|||
typedef union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 2132 of yacc.c */
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 26 "arangod/Ahuacatl/ahuacatl-grammar.y"
|
||||
|
||||
TRI_aql_node_t* node;
|
||||
|
@ -106,8 +108,8 @@ typedef union YYSTYPE
|
|||
|
||||
|
||||
|
||||
/* Line 2132 of yacc.c */
|
||||
#line 111 "arangod/Ahuacatl/ahuacatl-grammar.h"
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 113 "arangod/Ahuacatl/ahuacatl-grammar.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
|
|
@ -149,6 +149,7 @@ void Ahuacatlerror (YYLTYPE* locp, TRI_aql_context_t* const context, const char*
|
|||
%type <node> operator_binary;
|
||||
%type <node> operator_ternary;
|
||||
%type <node> function_call;
|
||||
%type <strval> function_name;
|
||||
%type <node> optional_function_call_arguments;
|
||||
%type <node> function_arguments_list;
|
||||
%type <node> compound_type;
|
||||
|
@ -459,10 +460,30 @@ expression:
|
|||
}
|
||||
;
|
||||
|
||||
function_call:
|
||||
function_name:
|
||||
T_STRING {
|
||||
$$ = $1;
|
||||
|
||||
if ($$ == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
| function_name T_COLON T_STRING {
|
||||
if ($1 == NULL || $3 == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = TRI_RegisterString3Aql(context, $1, ":", $3);
|
||||
|
||||
if ($$ == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
function_call:
|
||||
function_name {
|
||||
TRI_aql_node_t* node;
|
||||
/* function call */
|
||||
|
||||
if (! TRI_PushStackParseAql(context, $1)) {
|
||||
ABORT_OOM
|
||||
|
|
|
@ -183,6 +183,8 @@ const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) {
|
|||
return "parameter";
|
||||
case TRI_AQL_NODE_FCALL:
|
||||
return "function call";
|
||||
case TRI_AQL_NODE_FCALL_USER:
|
||||
return "function call (user)";
|
||||
}
|
||||
|
||||
assert(false);
|
||||
|
|
|
@ -182,7 +182,8 @@ typedef enum {
|
|||
TRI_AQL_NODE_REFERENCE,
|
||||
TRI_AQL_NODE_ATTRIBUTE,
|
||||
TRI_AQL_NODE_PARAMETER,
|
||||
TRI_AQL_NODE_FCALL
|
||||
TRI_AQL_NODE_FCALL,
|
||||
TRI_AQL_NODE_FCALL_USER
|
||||
}
|
||||
TRI_aql_node_type_e;
|
||||
|
||||
|
|
|
@ -148,9 +148,13 @@ static TRI_aql_node_t* DumpNode (TRI_aql_statement_walker_t* const walker,
|
|||
case TRI_AQL_NODE_ATTRIBUTE_ACCESS:
|
||||
DumpString(state, node);
|
||||
break;
|
||||
|
||||
case TRI_AQL_NODE_FCALL:
|
||||
printf("name: %s\n", TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node)));
|
||||
break;
|
||||
case TRI_AQL_NODE_FCALL_USER:
|
||||
printf("name: %s\n", TRI_AQL_NODE_STRING(node));
|
||||
break;
|
||||
|
||||
case TRI_AQL_NODE_SORT_ELEMENT:
|
||||
PrintIndent(state);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "Basics/ConditionLocker.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/MutexLocker.h"
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Logger/Logger.h"
|
||||
|
@ -121,6 +123,8 @@ namespace {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationV8::V8Context::addGlobalContextMethod (string const& method) {
|
||||
MUTEX_LOCKER(_globalMethodsLock);
|
||||
|
||||
_globalMethods.push_back(method);
|
||||
}
|
||||
|
||||
|
@ -130,6 +134,8 @@ void ApplicationV8::V8Context::addGlobalContextMethod (string const& method) {
|
|||
|
||||
void ApplicationV8::V8Context::handleGlobalContextMethods () {
|
||||
v8::HandleScope scope;
|
||||
|
||||
MUTEX_LOCKER(_globalMethodsLock);
|
||||
|
||||
for (vector<string>::iterator i = _globalMethods.begin(); i != _globalMethods.end(); ++i) {
|
||||
string const& func = *i;
|
||||
|
@ -278,6 +284,7 @@ ApplicationV8::V8Context* ApplicationV8::enterContext (bool initialise) {
|
|||
context->_isolate->Enter();
|
||||
context->_context->Enter();
|
||||
|
||||
LOGGER_TRACE("entering V8 context " << context->_id);
|
||||
context->handleGlobalContextMethods();
|
||||
|
||||
if (_developmentMode && ! initialise) {
|
||||
|
@ -300,6 +307,7 @@ void ApplicationV8::exitContext (V8Context* context) {
|
|||
V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
|
||||
assert(gc != 0);
|
||||
|
||||
LOGGER_TRACE("leaving V8 context " << context->_id);
|
||||
double lastGc = gc->getLastGcStamp();
|
||||
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
@ -337,24 +345,8 @@ void ApplicationV8::exitContext (V8Context* context) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationV8::addGlobalContextMethod (string const& method) {
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
||||
for (vector<V8Context*>::iterator i = _freeContexts.begin(); i != _freeContexts.end(); ++i) {
|
||||
V8Context* context = *i;
|
||||
|
||||
context->addGlobalContextMethod(method);
|
||||
}
|
||||
|
||||
for (vector<V8Context*>::iterator i = _dirtyContexts.begin(); i != _dirtyContexts.end(); ++i) {
|
||||
V8Context* context = *i;
|
||||
|
||||
context->addGlobalContextMethod(method);
|
||||
}
|
||||
|
||||
for (set<V8Context*>::iterator i = _busyContexts.begin(); i != _busyContexts.end(); ++i) {
|
||||
V8Context* context = *i;
|
||||
|
||||
context->addGlobalContextMethod(method);
|
||||
for (size_t i = 0; i < _nrInstances; ++i) {
|
||||
_contexts[i]->addGlobalContextMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,12 @@ namespace triagens {
|
|||
|
||||
void handleGlobalContextMethods ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief mutex to protect _globalMethods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
basics::Mutex _globalMethodsLock;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief open global methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -2254,17 +2254,17 @@ static v8::Handle<v8::Value> JS_PersistGeneralCursor (v8::Arguments const& argv)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the next x rows from the cursor in one go
|
||||
/// @brief return all following rows from the cursor in one go
|
||||
///
|
||||
/// This function constructs multiple rows at once and should be preferred over
|
||||
/// hasNext()...next() when iterating over bigger result sets
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv) {
|
||||
static v8::Handle<v8::Value> JS_ToArrayGeneralCursor (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (argv.Length() != 0) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "getRows()");
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "toArray()");
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase();
|
||||
|
@ -2319,6 +2319,15 @@ static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv)
|
|||
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief alias for toArray()
|
||||
/// @deprecated
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv) {
|
||||
return JS_ToArrayGeneralCursor(argv);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return max number of results per transfer for cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -6658,6 +6667,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
|
|||
TRI_AddProtoMethodVocbase(pt, "id", JS_IdGeneralCursor);
|
||||
TRI_AddProtoMethodVocbase(pt, "next", JS_NextGeneralCursor);
|
||||
TRI_AddProtoMethodVocbase(pt, "persist", JS_PersistGeneralCursor);
|
||||
TRI_AddProtoMethodVocbase(pt, "toArray", JS_ToArrayGeneralCursor);
|
||||
TRI_AddProtoMethodVocbase(pt, "unuse", JS_UnuseGeneralCursor);
|
||||
|
||||
rt = ft->InstanceTemplate();
|
||||
|
|
|
@ -220,7 +220,7 @@ static bool Compactifier (TRI_df_marker_t const* marker, void* data, TRI_datafil
|
|||
TRI_document_collection_t* doc;
|
||||
TRI_primary_collection_t* primary;
|
||||
TRI_voc_fid_t fid;
|
||||
TRI_voc_tid_t tid;
|
||||
// TRI_voc_tid_t tid;
|
||||
int res;
|
||||
|
||||
doc = data;
|
||||
|
@ -232,7 +232,7 @@ static bool Compactifier (TRI_df_marker_t const* marker, void* data, TRI_datafil
|
|||
TRI_doc_document_key_marker_t const* d = (TRI_doc_document_key_marker_t const*) marker;
|
||||
bool deleted;
|
||||
|
||||
tid = d->_tid;
|
||||
// tid = d->_tid;
|
||||
|
||||
// check if the document is still active
|
||||
TRI_READ_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary);
|
||||
|
@ -292,7 +292,7 @@ static bool Compactifier (TRI_df_marker_t const* marker, void* data, TRI_datafil
|
|||
// deletion
|
||||
else if (marker->_type == TRI_DOC_MARKER_KEY_DELETION) {
|
||||
TRI_doc_deletion_key_marker_t const* d = (TRI_doc_deletion_key_marker_t const*) marker;
|
||||
tid = d->_tid;
|
||||
// tid = d->_tid;
|
||||
|
||||
// write to compactor files
|
||||
res = CopyDocument(doc, marker, &result, &fid);
|
||||
|
|
|
@ -467,7 +467,10 @@ typedef struct TRI_doc_begin_transaction_marker_s {
|
|||
TRI_df_marker_t base;
|
||||
|
||||
TRI_voc_tid_t _tid;
|
||||
uint16_t _numCollections;
|
||||
uint32_t _numCollections;
|
||||
#ifdef TRI_PADDING_32
|
||||
char _padding_begin_marker[4];
|
||||
#endif
|
||||
}
|
||||
TRI_doc_begin_transaction_marker_t;
|
||||
|
||||
|
|
|
@ -110,6 +110,9 @@
|
|||
"ERROR_QUERY_FAIL_CALLED" : { "code" : 1569, "message" : "FAIL(%s) called" },
|
||||
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
|
||||
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
|
||||
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
|
||||
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
|
||||
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function not found" },
|
||||
"ERROR_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" },
|
||||
"ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" },
|
||||
"ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" },
|
||||
|
|
|
@ -80,6 +80,19 @@
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the AQL user functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal.reloadAqlFunctions = function () {
|
||||
if (typeof internal.arango !== 'undefined') {
|
||||
internal.arango.POST("/_admin/aql/reload", "");
|
||||
return;
|
||||
}
|
||||
|
||||
throw "not connected";
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief flushes the module cache of the server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -158,6 +158,21 @@ actions.defineHttp({
|
|||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the AQL user functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
actions.defineHttp({
|
||||
url : "_admin/aql/reload",
|
||||
context : "admin",
|
||||
prefix : false,
|
||||
|
||||
callback : function (req, res) {
|
||||
internal.reloadAqlFunctions();
|
||||
actions.resultOk(req, res, actions.HTTP_OK);
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @fn JSF_GET_admin_routing_reloads
|
||||
/// @brief reloads the routing information
|
||||
|
|
|
@ -80,6 +80,19 @@
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the AQL user functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal.reloadAqlFunctions = function () {
|
||||
if (typeof internal.arango !== 'undefined') {
|
||||
internal.arango.POST("/_admin/aql/reload", "");
|
||||
return;
|
||||
}
|
||||
|
||||
throw "not connected";
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief flushes the module cache of the server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -110,6 +110,9 @@
|
|||
"ERROR_QUERY_FAIL_CALLED" : { "code" : 1569, "message" : "FAIL(%s) called" },
|
||||
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
|
||||
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
|
||||
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
|
||||
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
|
||||
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function not found" },
|
||||
"ERROR_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" },
|
||||
"ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" },
|
||||
"ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" },
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
|
||||
/*global require, exports */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief AQL user functions management
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var internal = require("internal");
|
||||
var arangodb = require("org/arangodb");
|
||||
var db = arangodb.db;
|
||||
var ArangoError = require("org/arangodb/arango-error").ArangoError;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- module "org/arangodb/aql/functions"
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate a function name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var validateName = function (name) {
|
||||
if (typeof name !== 'string' ||
|
||||
! name.match(/^[a-zA-Z0-9_]+(:[a-zA-Z0-9_]+)+$/) ||
|
||||
name.substr(0, 1) === "_") {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_QUERY_FUNCTION_INVALID_NAME.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_QUERY_FUNCTION_INVALID_NAME.message;
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate user function code
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var stringifyFunction = function (code, name) {
|
||||
if (typeof code === 'function') {
|
||||
code = String(code);
|
||||
}
|
||||
|
||||
if (typeof code === 'string') {
|
||||
code = "(" + code + ")";
|
||||
|
||||
if (! internal.parse) {
|
||||
// no parsing possible. assume always valid
|
||||
return code;
|
||||
}
|
||||
|
||||
try {
|
||||
if (internal.parse(code, name)) {
|
||||
// parsing successful
|
||||
return code;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
// fall-through intentional
|
||||
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_QUERY_FUNCTION_INVALID_CODE.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_QUERY_FUNCTION_INVALID_CODE.message;
|
||||
|
||||
throw err;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the _aqlfunctions collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var getStorage = function () {
|
||||
var functions = db._collection("_aqlfunctions");
|
||||
|
||||
if (functions === null) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code;
|
||||
err.errorMessage = "collection _aqlfunctions not found";
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
return functions;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief delete an existing AQL user function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var unregisterFunction = function (name) {
|
||||
var func = null;
|
||||
|
||||
validateName(name);
|
||||
|
||||
try {
|
||||
func = getStorage().document(name.toUpperCase());
|
||||
}
|
||||
catch (err1) {
|
||||
}
|
||||
|
||||
if (func === null) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_QUERY_FUNCTION_NOT_FOUND.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_QUERY_FUNCTION_NOT_FOUND.message;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
getStorage().remove(func._id);
|
||||
internal.reloadAqlFunctions();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an AQL user function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var registerFunction = function (name, code, isDeterministic) {
|
||||
// validate input
|
||||
validateName(name);
|
||||
code = stringifyFunction(code, name);
|
||||
|
||||
try {
|
||||
unregisterFunction(name);
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
|
||||
var data = {
|
||||
_key: name.toUpperCase(),
|
||||
name: name,
|
||||
code: code,
|
||||
isDeterministic: isDeterministic || false
|
||||
};
|
||||
|
||||
getStorage().save(data);
|
||||
internal.reloadAqlFunctions();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the AQL user functons
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var reloadFunctions = function () {
|
||||
throw "cannot use abstract reload function";
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- module exports
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.register = registerFunction;
|
||||
exports.unregister = unregisterFunction;
|
||||
exports.reload = reloadFunctions;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\|/\\*jslint"
|
||||
// End:
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 80 */
|
||||
/*global require, assertEqual, assertTrue */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test the AQL user functions management
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var jsunity = require("jsunity");
|
||||
var arangodb = require("org/arangodb");
|
||||
var ERRORS = arangodb.errors;
|
||||
var db = arangodb.db;
|
||||
|
||||
var aqlfunctions = require("org/arangodb/aql/functions");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- AQL user functions tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function AqlFunctionsSuite () {
|
||||
|
||||
var unregister = function (name) {
|
||||
try {
|
||||
aqlfunctions.unregister(name);
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
setUp : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tear down
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tearDown : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterFunc1 : function () {
|
||||
unregister("UnitTests:tryme:foo");
|
||||
aqlfunctions.register("UnitTests:tryme:foo", function (what) { return what * 2; }, true);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterFunc2 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 2; }, true);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterString1 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", "function (what) { return what * 2; }", true);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterString2 : function () {
|
||||
unregister("UnitTests:tryme:foo");
|
||||
aqlfunctions.register("UnitTests:tryme:foo", "function (what) { return what * 2; }", true);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief re-register a function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testReRegister : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 2; }, true);
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 2; }, true);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidName1 : function () {
|
||||
try {
|
||||
aqlfunctions.register("foo", function (what) { return what * 2; }, true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_NAME.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidName2 : function () {
|
||||
try {
|
||||
aqlfunctions.register("_test", function (what) { return what * 2; }, true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_NAME.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidName3 : function () {
|
||||
try {
|
||||
aqlfunctions.register("_test:foo", function (what) { return what * 2; }, true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_NAME.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidName4 : function () {
|
||||
try {
|
||||
aqlfunctions.register("test:", function (what) { return what * 2; }, true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_NAME.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid body
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidCode1 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
try {
|
||||
aqlfunctions.register("UnitTests:tryme", "function (what) { ", true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_CODE.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function with an invalid body
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRegisterInvalidCode2 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
try {
|
||||
aqlfunctions.register("UnitTests:tryme", 1234, true);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_INVALID_CODE.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and unregister it
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUnregister : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 4; }, true);
|
||||
aqlfunctions.unregister("UnitTests:tryme");
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief unregister an unknown function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUnregisterUnknown : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
|
||||
try {
|
||||
aqlfunctions.unregister("UnitTests:tryme");
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(ERRORS.ERROR_QUERY_FUNCTION_NOT_FOUND.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQuery1 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 2; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ 8 ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQuery2 : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
unregister("UnitTests:foo");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return what * 2; }, true);
|
||||
aqlfunctions.register("UnitTests:foo", function (what) { return what * 4; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4) + UnitTests:foo(9)" }).execute().toArray();
|
||||
assertEqual([ 4 * 2 + 9 * 4 ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnUndefined : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ null ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnNan : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return 1 / 0; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ null ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnNull : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return null; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ null ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnTrue : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return true; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ true ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnFalse : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return false; }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme(4)" }).execute().toArray();
|
||||
assertEqual([ false ], actual);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a function and run a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testQueryReturnComplex : function () {
|
||||
unregister("UnitTests:tryme");
|
||||
aqlfunctions.register("UnitTests:tryme", function (what) { return [ true, false, null, 1, 2, -4, [ 5.5, { a: 1, "b": "def" } ] ] }, true);
|
||||
|
||||
var actual = db._createStatement({ query: "RETURN UnitTests:tryme()" }).execute().toArray();
|
||||
assertEqual([ [ true, false, null, 1, 2, -4, [ 5.5, { a: 1, "b": "def" } ] ] ], actual);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- main
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(AqlFunctionsSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
|
@ -164,6 +164,32 @@ function CollectionVolatileSuite () {
|
|||
internal.wait(4);
|
||||
assertEqual(true, c.properties().isVolatile);
|
||||
assertEqual(0, c.count());
|
||||
assertEqual([ ], c.toArray());
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testCompaction : function () {
|
||||
var c = internal.db._create(cn, { isVolatile : true, journalSize: 1024 * 1024 });
|
||||
assertEqual(true, c.properties().isVolatile);
|
||||
|
||||
for (var i = 0; i < 10000; ++i) {
|
||||
c.save({"test": "the quick brown fox jumped over the lazy dog", "foo" : "bar"});
|
||||
}
|
||||
|
||||
assertEqual(10000, c.count());
|
||||
c.truncate();
|
||||
c.save({"test": 1});
|
||||
assertEqual(1, c.count());
|
||||
c.truncate();
|
||||
|
||||
c.unload();
|
||||
|
||||
internal.wait(5);
|
||||
assertEqual(0, c.count());
|
||||
assertEqual([ ], c.toArray());
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -191,6 +191,22 @@
|
|||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the AQL user functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (typeof SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION === "undefined") {
|
||||
internal.reloadAqlFunctions = function () {
|
||||
require("org/arangodb/ahuacatl").reload();
|
||||
};
|
||||
}
|
||||
else {
|
||||
internal.reloadAqlFunctions = function () {
|
||||
internal.executeGlobalContextFunction("require(\"org/arangodb/ahuacatl\").reload();");
|
||||
require("org/arangodb/ahuacatl").reload();
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes a string in all V8 contexts
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -2022,7 +2022,10 @@ exports.HTTP_NOT_FOUND = 404;
|
|||
exports.HTTP_METHOD_NOT_ALLOWED = 405;
|
||||
exports.HTTP_CONFLICT = 409;
|
||||
exports.HTTP_PRECONDITION_FAILED = 412;
|
||||
exports.HTTP_ENTITY_TOO_LARGE = 413;
|
||||
exports.HTTP_I_AM_A_TEAPOT = 418;
|
||||
exports.HTTP_UNPROCESSABLE_ENTIT = 422;
|
||||
exports.HTTP_HEADER_TOO_LARGE = 431;
|
||||
|
||||
// HTTP 5xx
|
||||
exports.HTTP_SERVER_ERROR = 500;
|
||||
|
|
|
@ -34,8 +34,6 @@ var INTERNAL = require("internal");
|
|||
var TRAVERSAL = require("org/arangodb/graph/traversal");
|
||||
var ArangoError = require("org/arangodb/arango-error").ArangoError;
|
||||
|
||||
var RegexCache = { 'i' : { }, '' : { } };
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -45,6 +43,18 @@ var RegexCache = { 'i' : { }, '' : { } };
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief cache for compiled regexes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var RegexCache = { };
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief user functions cache
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var UserFunctions = { };
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type weight used for sorting and comparing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -209,6 +219,44 @@ function CLONE (obj) {
|
|||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief box a value into the AQL datatype system
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function FIX_VALUE (value) {
|
||||
var type = typeof(value), i;
|
||||
|
||||
if (value === undefined ||
|
||||
value === null ||
|
||||
(type === 'number' && (isNaN(value) || ! isFinite(value)))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type === 'boolean' || type === 'string' || type === 'number') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (i = 0; i < value.length; ++i) {
|
||||
value[i] = FIX_VALUE(value[i]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (type === 'object') {
|
||||
for (i in value) {
|
||||
if (value.hasOwnProperty(i)) {
|
||||
value[i] = FIX_VALUE(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the sort type of an operand
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -317,6 +365,20 @@ function FCALL (name, parameters) {
|
|||
return name.apply(null, parameters);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief call a user function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function FCALL_USER (name, parameters) {
|
||||
if (UserFunctions.hasOwnProperty(name)) {
|
||||
var result = UserFunctions[name].func.apply(null, parameters);
|
||||
|
||||
return FIX_VALUE(result);
|
||||
}
|
||||
|
||||
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_NOT_FOUND, name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the numeric value or undefined if it is out of range
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3220,6 +3282,71 @@ function GRAPH_EDGES (edgeCollection,
|
|||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- setup / reset functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Ahuacatl
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reset the regex cache
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function resetRegexCache () {
|
||||
RegexCache = { 'i' : { }, '' : { } };
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reset the user functions and reload them from the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function reloadUserFunctions () {
|
||||
var c;
|
||||
|
||||
UserFunctions = { };
|
||||
|
||||
c = INTERNAL.db._collection("_aqlfunctions");
|
||||
if (c === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
c.toArray().forEach(function (f) {
|
||||
var code;
|
||||
|
||||
code = "(function() { var callback = " + f.code + "; return callback; })();";
|
||||
|
||||
try {
|
||||
var res = INTERNAL.executeScript(code, undefined, "(user function " + f._key + ")");
|
||||
|
||||
UserFunctions[f._key.toUpperCase()] = {
|
||||
name: f._key,
|
||||
func: res,
|
||||
isDeterministic: f.isDeterministic || false
|
||||
};
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_INVALID_CODE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reset the query engine
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function resetEngine () {
|
||||
resetRegexCache();
|
||||
reloadUserFunctions();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- MODULE EXPORTS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -3230,6 +3357,7 @@ function GRAPH_EDGES (edgeCollection,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.FCALL = FCALL;
|
||||
exports.FCALL_USER = FCALL_USER;
|
||||
exports.KEYS = KEYS;
|
||||
exports.GET_INDEX = GET_INDEX;
|
||||
exports.DOCUMENT_MEMBER = DOCUMENT_MEMBER;
|
||||
|
@ -3331,10 +3459,16 @@ exports.MATCHES = MATCHES;
|
|||
exports.PASSTHRU = PASSTHRU;
|
||||
exports.FAIL = FAIL;
|
||||
|
||||
exports.reload = reloadUserFunctions;
|
||||
|
||||
// initialise the query engine
|
||||
resetEngine();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -59,7 +59,10 @@ var Application,
|
|||
/// a constraint and a method. For example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// internal.createUrlObject('/lecker/gans', null, 'get');
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal.createUrlObject = function (url, constraint, method) {
|
||||
|
@ -89,10 +92,13 @@ internal.createUrlObject = function (url, constraint, method) {
|
|||
/// * **The Template Collection:** More information in the template section
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app = new Application({
|
||||
/// urlPrefix: "/wiese",
|
||||
/// templateCollection: "my_templates"
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Application = function (options) {
|
||||
|
@ -170,9 +176,12 @@ _.extend(Application.prototype, {
|
|||
/// object).
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.handleRequest("get", "/gaense", function (req, res) {
|
||||
/// //handle the request
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
handleRequest: function (method, route, callback) {
|
||||
|
@ -216,9 +225,12 @@ _.extend(Application.prototype, {
|
|||
/// See above for the arguments you can give. An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.get('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
get: function (route, callback) {
|
||||
'use strict';
|
||||
|
@ -233,9 +245,12 @@ _.extend(Application.prototype, {
|
|||
/// See above for the arguments you can give. An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.post('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
post: function (route, callback) {
|
||||
'use strict';
|
||||
|
@ -250,9 +265,12 @@ _.extend(Application.prototype, {
|
|||
/// See above for the arguments you can give. An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.put('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
put: function (route, callback) {
|
||||
'use strict';
|
||||
|
@ -267,9 +285,12 @@ _.extend(Application.prototype, {
|
|||
/// See above for the arguments you can give. An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.patch('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
patch: function (route, callback) {
|
||||
'use strict';
|
||||
|
@ -288,6 +309,8 @@ _.extend(Application.prototype, {
|
|||
/// for this very reason.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app['delete']('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
|
@ -295,6 +318,7 @@ _.extend(Application.prototype, {
|
|||
/// app.del('/gaense/stall', function (req, res) {
|
||||
/// // Take this request and deal with it!
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
'delete': function (route, callback) {
|
||||
|
@ -319,9 +343,12 @@ _.extend(Application.prototype, {
|
|||
/// An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.before('/high/way', function(req, res) {
|
||||
/// //Do some crazy request logging
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
before: function (path, func) {
|
||||
|
@ -350,9 +377,12 @@ _.extend(Application.prototype, {
|
|||
/// An example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.after('/high/way', function(req, res) {
|
||||
/// //Do some crazy response logging
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
after: function (path, func) {
|
||||
|
@ -381,9 +411,12 @@ _.extend(Application.prototype, {
|
|||
/// blocks.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.helper("link_to", function (identifier) {
|
||||
/// return urlRepository[identifier];
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
helper: function (name, func) {
|
||||
|
@ -400,7 +433,10 @@ _.extend(Application.prototype, {
|
|||
/// This is a shortcut to add the middleware to your application:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.accepts(["json"], "json");
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
accepts: function (allowedFormats, defaultFormat) {
|
||||
|
@ -446,12 +482,15 @@ _.extend(RequestContext.prototype, {
|
|||
/// You can also provide a description of this parameter.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.get("/foxx/:id", function {
|
||||
/// // Do something
|
||||
/// }).pathParam("id", {
|
||||
/// description: "Id of the Foxx",
|
||||
/// dataType: "int"
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pathParam: function (paramName, attributes) {
|
||||
|
@ -489,6 +528,8 @@ _.extend(RequestContext.prototype, {
|
|||
/// if you can provide the parameter multiple times.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// app.get("/foxx", function {
|
||||
/// // Do something
|
||||
/// }).queryParam("id", {
|
||||
|
@ -497,6 +538,7 @@ _.extend(RequestContext.prototype, {
|
|||
/// required: true,
|
||||
/// allowMultiple: false
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
queryParam: function (paramName, attributes) {
|
||||
|
@ -632,7 +674,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
|
|||
/// Set the status code of your response, for example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
/// response.status(404);
|
||||
///
|
||||
/// @code
|
||||
/// response.status(404);
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
status: function (code) {
|
||||
this.responseCode = code;
|
||||
|
@ -645,6 +690,8 @@ BaseMiddleware = function (templateCollection, helperCollection) {
|
|||
/// Set a header attribute, for example:
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// response.set("Content-Length", 123);
|
||||
/// response.set("Content-Type", "text/plain");
|
||||
///
|
||||
|
@ -654,6 +701,7 @@ BaseMiddleware = function (templateCollection, helperCollection) {
|
|||
/// "Content-Length": "123",
|
||||
/// "Content-Type": "text/plain"
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
set: function (key, value) {
|
||||
|
@ -683,7 +731,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
|
|||
/// JSON encoded object you provided.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// response.json({'born': 'December 12, 1915'});
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
json: function (obj) {
|
||||
|
@ -725,7 +776,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
|
|||
/// ViewHelper section.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// response.render("high/way", {username: 'Application'})
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
render: function (templatePath, data) {
|
||||
var template;
|
||||
|
@ -853,9 +907,12 @@ FormatMiddleware = function (allowedFormats, defaultFormat) {
|
|||
/// as an object.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// instance = new Model({
|
||||
/// a: 1
|
||||
/// });
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Model = function (attributes) {
|
||||
|
@ -871,11 +928,14 @@ _.extend(Model.prototype, {
|
|||
///
|
||||
/// Get the value of an attribute
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// instance = new Model({
|
||||
/// a: 1
|
||||
/// });
|
||||
///
|
||||
/// instance.get("a");
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
get: function (attributeName) {
|
||||
|
@ -888,11 +948,14 @@ _.extend(Model.prototype, {
|
|||
///
|
||||
/// Set the value of an attribute
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// instance = new Model({
|
||||
/// a: 1
|
||||
/// });
|
||||
///
|
||||
/// instance.set("a", 2);
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
set: function (attributeName, value) {
|
||||
|
@ -905,12 +968,15 @@ _.extend(Model.prototype, {
|
|||
///
|
||||
/// Returns true if the attribute is set to a non-null or non-undefined value.
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// instance = new Model({
|
||||
/// a: 1
|
||||
/// });
|
||||
///
|
||||
/// instance.has("a"); //=> true
|
||||
/// instance.has("b"); //=> false
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
has: function (attributeName) {
|
||||
|
@ -949,7 +1015,10 @@ Model.extend = backbone_helpers.extend;
|
|||
/// If you initialize a model, you can give it initial data as an object.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @code
|
||||
/// instance = new Repository(prefix, collection, modelPrototype);
|
||||
/// @endcode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Repository = function (prefix, collection, modelPrototype) {
|
||||
|
|
|
@ -344,6 +344,11 @@
|
|||
|
||||
return true;
|
||||
});
|
||||
|
||||
// set up the collection _aqlfunctions
|
||||
addTask("setupAqlFunctions", "setup _aqlfunctions collection", function () {
|
||||
return createSystemCollection("_aqlfunctions", { waitForSync : false });
|
||||
});
|
||||
|
||||
// loop through all tasks and execute them
|
||||
console.log("Found " + allTasks.length + " defined task(s), "
|
||||
|
|
|
@ -141,6 +141,14 @@ ERROR_QUERY_FAIL_CALLED,1569,"FAIL(%s) called","Will be raised when the function
|
|||
ERROR_QUERY_GEO_INDEX_MISSING,1570,"no suitable geo index found for geo restriction on '%s'","Will be raised when a geo restriction was specified but no suitable geo index is found to resolve it."
|
||||
ERROR_QUERY_FULLTEXT_INDEX_MISSING,1571,"no suitable fulltext index found for fulltext query on '%s'","Will be raised when a fulltext query is performed on a collection without a suitable fulltext index."
|
||||
|
||||
################################################################################
|
||||
## AQL user functions
|
||||
################################################################################
|
||||
|
||||
ERROR_QUERY_FUNCTION_INVALID_NAME,1580,"invalid user function name","Will be raised when a user function with an invalid name is registered."
|
||||
ERROR_QUERY_FUNCTION_INVALID_CODE,1581,"invalid user function code","Will be raised when a user function is registered with invalid code."
|
||||
ERROR_QUERY_FUNCTION_NOT_FOUND,1582,"user function not found","Will be raised when a user function is accessed but not found."
|
||||
|
||||
################################################################################
|
||||
## ArangoDB cursor errors
|
||||
################################################################################
|
||||
|
|
|
@ -106,6 +106,9 @@ void TRI_InitialiseErrorMessages (void) {
|
|||
REG_ERROR(ERROR_QUERY_FAIL_CALLED, "FAIL(%s) called");
|
||||
REG_ERROR(ERROR_QUERY_GEO_INDEX_MISSING, "no suitable geo index found for geo restriction on '%s'");
|
||||
REG_ERROR(ERROR_QUERY_FULLTEXT_INDEX_MISSING, "no suitable fulltext index found for fulltext query on '%s'");
|
||||
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_NAME, "invalid user function name");
|
||||
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_CODE, "invalid user function code");
|
||||
REG_ERROR(ERROR_QUERY_FUNCTION_NOT_FOUND, "user function not found");
|
||||
REG_ERROR(ERROR_CURSOR_NOT_FOUND, "cursor not found");
|
||||
REG_ERROR(ERROR_TRANSACTION_INCOMPLETE, "transaction definition is incomplete");
|
||||
REG_ERROR(ERROR_TRANSACTION_INVALID_STATE, "invalid transaction state");
|
||||
|
|
|
@ -230,6 +230,12 @@ extern "C" {
|
|||
/// - 1571: @LIT{no suitable fulltext index found for fulltext query on '\%s'}
|
||||
/// Will be raised when a fulltext query is performed on a collection without
|
||||
/// a suitable fulltext index.
|
||||
/// - 1580: @LIT{invalid user function name}
|
||||
/// Will be raised when a user function with an invalid name is registered.
|
||||
/// - 1581: @LIT{invalid user function code}
|
||||
/// Will be raised when a user function is registered with invalid code.
|
||||
/// - 1582: @LIT{user function not found}
|
||||
/// Will be raised when a user function is accessed but not found.
|
||||
/// - 1600: @LIT{cursor not found}
|
||||
/// Will be raised when a cursor is requested via its id but a cursor with
|
||||
/// that id cannot be found.
|
||||
|
@ -1372,6 +1378,36 @@ void TRI_InitialiseErrorMessages (void);
|
|||
|
||||
#define TRI_ERROR_QUERY_FULLTEXT_INDEX_MISSING (1571)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1580: ERROR_QUERY_FUNCTION_INVALID_NAME
|
||||
///
|
||||
/// invalid user function name
|
||||
///
|
||||
/// Will be raised when a user function with an invalid name is registered.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_QUERY_FUNCTION_INVALID_NAME (1580)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1581: ERROR_QUERY_FUNCTION_INVALID_CODE
|
||||
///
|
||||
/// invalid user function code
|
||||
///
|
||||
/// Will be raised when a user function is registered with invalid code.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_QUERY_FUNCTION_INVALID_CODE (1581)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1582: ERROR_QUERY_FUNCTION_NOT_FOUND
|
||||
///
|
||||
/// user function not found
|
||||
///
|
||||
/// Will be raised when a user function is accessed but not found.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_QUERY_FUNCTION_NOT_FOUND (1582)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1600: ERROR_CURSOR_NOT_FOUND
|
||||
///
|
||||
|
|
|
@ -51,7 +51,6 @@ using namespace std;
|
|||
|
||||
string HttpResponse::responseString (HttpResponseCode code) {
|
||||
switch (code) {
|
||||
|
||||
// Success 2xx
|
||||
case OK: return "200 OK";
|
||||
case CREATED: return "201 Created";
|
||||
|
@ -77,6 +76,7 @@ string HttpResponse::responseString (HttpResponseCode code) {
|
|||
case LENGTH_REQUIRED: return "411 Length Required";
|
||||
case PRECONDITION_FAILED: return "412 Precondition Failed";
|
||||
case ENTITY_TOO_LARGE: return "413 Request Entity Too Large";
|
||||
case I_AM_A_TEAPOT: return "418 I'm a teapot";
|
||||
case UNPROCESSABLE_ENTITY: return "422 Unprocessable Entity";
|
||||
case HEADER_TOO_LARGE: return "431 Request Header Fields Too Large";
|
||||
|
||||
|
@ -120,6 +120,7 @@ HttpResponse::HttpResponseCode HttpResponse::responseCode (const string& str) {
|
|||
case 405: return METHOD_NOT_ALLOWED;
|
||||
case 409: return CONFLICT;
|
||||
case 412: return PRECONDITION_FAILED;
|
||||
case 418: return I_AM_A_TEAPOT;
|
||||
case 422: return UNPROCESSABLE_ENTITY;
|
||||
|
||||
case 500: return SERVER_ERROR;
|
||||
|
|
|
@ -100,6 +100,7 @@ namespace triagens {
|
|||
LENGTH_REQUIRED = 411,
|
||||
PRECONDITION_FAILED = 412,
|
||||
ENTITY_TOO_LARGE = 413,
|
||||
I_AM_A_TEAPOT = 418,
|
||||
UNPROCESSABLE_ENTITY = 422,
|
||||
HEADER_TOO_LARGE = 431,
|
||||
|
||||
|
|
Loading…
Reference in New Issue