1
0
Fork 0

Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel

This commit is contained in:
Frank Celler 2013-04-05 13:25:04 +02:00
commit 71bf83be1b
38 changed files with 2108 additions and 952 deletions

View File

@ -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. The attributes property is the internal hash containing the model's state.
#### Foxx.Model#toJSON #### Foxx.Model#toJSON
@copydetails jsf_foxx_model_toJSON @copydetails JSF_foxx_model_toJSON
## Foxx.Repository ## Foxx.Repository

View File

@ -210,6 +210,7 @@ endif
################################################################################ ################################################################################
SHELL_COMMON = @top_srcdir@/js/common/tests/shell-require.js \ 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-attributes.js \
@top_srcdir@/js/common/tests/shell-collection.js \ @top_srcdir@/js/common/tests/shell-collection.js \
@top_srcdir@/js/common/tests/shell-collection-volatile.js \ @top_srcdir@/js/common/tests/shell-collection-volatile.js \

View File

@ -100,6 +100,64 @@ inline static void InitNode (TRI_aql_context_t* const context,
TRI_RegisterNodeContextAql(context, node); 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, TRI_aql_node_t* TRI_CreateNodeFcallAql (TRI_aql_context_t* const context,
const char* const name, const char* const name,
const TRI_aql_node_t* const parameters) { const TRI_aql_node_t* const parameters) {
CREATE_NODE(TRI_AQL_NODE_FCALL) TRI_aql_node_t* node;
char* upperName;
// initialise
TRI_AQL_NODE_DATA(node) = NULL;
if (name == NULL) { if (name == NULL) {
ABORT_OOM ABORT_OOM
} }
{ if (strchr(name, TRI_AQL_NAMESPACE_SEPARATOR_CHAR) != NULL) {
TRI_aql_function_t* function; upperName = TRI_UpperAsciiStringZ(TRI_CORE_MEM_ZONE, name);
TRI_associative_pointer_t* functions; }
else {
upperName = TRI_Concatenate2String(TRI_AQL_DEFAULT_PREFIX, TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, name));
}
assert(context->_vocbase); if (upperName == NULL) {
functions = context->_vocbase->_functions; ABORT_OOM
assert(functions); }
function = TRI_GetByExternalNameFunctionAql(functions, name); if (*upperName == '_') {
// default internal namespace
if (! function) { node = CreateNodeInternalFcall(context, name, upperName, parameters);
// function name is unknown TRI_Free(TRI_CORE_MEM_ZONE, upperName);
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_FUNCTION_NAME_UNKNOWN, name); }
return NULL; else {
} // user namespace
node = CreateNodeUserFcall(context, name, upperName, parameters);
// validate function call arguments // upperName intentionally not freed!
if (! TRI_ValidateArgsFunctionAql(context, function, parameters)) {
return NULL;
}
ADD_MEMBER(parameters)
TRI_AQL_NODE_DATA(node) = function;
} }
return node; return node;

View File

@ -1427,7 +1427,8 @@ static void ProcessArgList (TRI_aql_codegen_js_t* const generator,
ScopeOutput(generator, ", "); ScopeOutput(generator, ", ");
} }
if (parameter->_type == TRI_AQL_NODE_COLLECTION && if (function != NULL &&
parameter->_type == TRI_AQL_NODE_COLLECTION &&
TRI_ConvertParameterFunctionAql(function, i)) { TRI_ConvertParameterFunctionAql(function, i)) {
// collection arguments will be created as string argument => e.g. "users" // collection arguments will be created as string argument => e.g. "users"
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(parameter, 0); 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 /// @brief generate code for function calls
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void ProcessFcall (TRI_aql_codegen_js_t* const generator, static void ProcessFcallInternal (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) { const TRI_aql_node_t* const node) {
ScopeOutput(generator, "aql."); ScopeOutput(generator, "aql.");
ScopeOutput(generator, TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node))); ScopeOutput(generator, TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node)));
ScopeOutput(generator, "("); ScopeOutput(generator, "(");
@ -1889,6 +1890,19 @@ static void ProcessFcall (TRI_aql_codegen_js_t* const generator,
ScopeOutput(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 /// @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); ProcessTernary(generator, node);
break; break;
case TRI_AQL_NODE_FCALL: case TRI_AQL_NODE_FCALL:
ProcessFcall(generator, node); ProcessFcallInternal(generator, node);
break;
case TRI_AQL_NODE_FCALL_USER:
ProcessFcallUser(generator, node);
break; break;
case TRI_AQL_NODE_FOR: case TRI_AQL_NODE_FOR:
ProcessFor(generator, node); ProcessFor(generator, node);

View File

@ -423,7 +423,57 @@ char* TRI_RegisterStringAql (TRI_aql_context_t* const context,
ABORT_OOM 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; return copy;
} }

View File

@ -143,6 +143,23 @@ char* TRI_RegisterStringAql (TRI_aql_context_t* const,
const size_t, const size_t,
const bool); 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 /// @brief register a node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -603,6 +603,22 @@ bool TRI_NodeStringAql (TRI_string_buffer_t* const buffer,
return TRI_AppendStringStringBuffer(buffer, ")") == TRI_ERROR_NO_ERROR; 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: { case TRI_AQL_NODE_EXPAND: {
return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 3)); return TRI_NodeStringAql(buffer, TRI_AQL_NODE_MEMBER(node, 3));
} }

View File

@ -50,7 +50,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define REGISTER_FUNCTION(internalName, externalName, deterministic, group, argPattern, optimiseCallback) \ #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 /// @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) { for (i = 0; i < functions->_nrAlloc; ++i) {
TRI_aql_function_t* function = (TRI_aql_function_t*) functions->_table[i]; TRI_aql_function_t* function = (TRI_aql_function_t*) functions->_table[i];
if (!function) { if (function == NULL) {
continue; continue;
} }
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_argPattern);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function); 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 // normalize the name by upper-casing it
upperName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, externalName); upperName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, externalName);
if (upperName == NULL) { if (upperName == NULL) {
return NULL; return NULL;
} }
function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, (void*) upperName); function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, (void*) upperName);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, upperName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, upperName);
return function; return function;
} }
@ -744,21 +746,30 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
return false; return false;
} }
function->_externalName = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, externalName); function->_externalName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, externalName);
if (function->_externalName == NULL) { if (function->_externalName == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
return false; return false;
} }
// normalize name by upper-casing it // 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) { if (function->_internalName == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function);
return false; 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 // function already registered
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_externalName);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName); TRI_Free(TRI_UNKNOWN_MEM_ZONE, function->_internalName);
@ -768,7 +779,6 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions,
function->_isDeterministic = isDeterministic; function->_isDeterministic = isDeterministic;
function->_isGroup = isGroup; function->_isGroup = isGroup;
function->_argPattern = argPattern;
function->optimise = optimise; function->optimise = optimise;
// set minArgs and maxArgs // set minArgs and maxArgs

View File

@ -36,10 +36,55 @@
extern "C" { extern "C" {
#endif #endif
// -----------------------------------------------------------------------------
// --SECTION-- forward declarations
// -----------------------------------------------------------------------------
struct TRI_aql_context_s; struct TRI_aql_context_s;
struct TRI_aql_field_access_s; struct TRI_aql_field_access_s;
struct TRI_associative_pointer_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 /// @addtogroup Ahuacatl
/// @{ /// @{
@ -54,13 +99,26 @@ typedef struct TRI_aql_function_s {
char* _internalName; char* _internalName;
bool _isDeterministic; bool _isDeterministic;
bool _isGroup; bool _isGroup;
const char* _argPattern; char* _argPattern;
size_t _minArgs; size_t _minArgs;
size_t _maxArgs; size_t _maxArgs;
void (*optimise)(const TRI_aql_node_t* const, struct TRI_aql_context_s* const, struct TRI_aql_field_access_s*); void (*optimise)(const TRI_aql_node_t* const, struct TRI_aql_context_s* const, struct TRI_aql_field_access_s*);
} }
TRI_aql_function_t; TRI_aql_function_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Ahuacatl
/// @{
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the array with the function declarations /// @brief initialise the array with the function declarations
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -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 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 it under the terms of the GNU General Public License as published by
@ -96,7 +98,7 @@
typedef union YYSTYPE typedef union YYSTYPE
{ {
/* Line 2132 of yacc.c */ /* Line 1676 of yacc.c */
#line 26 "arangod/Ahuacatl/ahuacatl-grammar.y" #line 26 "arangod/Ahuacatl/ahuacatl-grammar.y"
TRI_aql_node_t* node; TRI_aql_node_t* node;
@ -106,8 +108,8 @@ typedef union YYSTYPE
/* Line 2132 of yacc.c */ /* Line 1676 of yacc.c */
#line 111 "arangod/Ahuacatl/ahuacatl-grammar.h" #line 113 "arangod/Ahuacatl/ahuacatl-grammar.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */

View File

@ -149,6 +149,7 @@ void Ahuacatlerror (YYLTYPE* locp, TRI_aql_context_t* const context, const char*
%type <node> operator_binary; %type <node> operator_binary;
%type <node> operator_ternary; %type <node> operator_ternary;
%type <node> function_call; %type <node> function_call;
%type <strval> function_name;
%type <node> optional_function_call_arguments; %type <node> optional_function_call_arguments;
%type <node> function_arguments_list; %type <node> function_arguments_list;
%type <node> compound_type; %type <node> compound_type;
@ -459,10 +460,30 @@ expression:
} }
; ;
function_call: function_name:
T_STRING { 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; TRI_aql_node_t* node;
/* function call */
if (! TRI_PushStackParseAql(context, $1)) { if (! TRI_PushStackParseAql(context, $1)) {
ABORT_OOM ABORT_OOM

View File

@ -183,6 +183,8 @@ const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) {
return "parameter"; return "parameter";
case TRI_AQL_NODE_FCALL: case TRI_AQL_NODE_FCALL:
return "function call"; return "function call";
case TRI_AQL_NODE_FCALL_USER:
return "function call (user)";
} }
assert(false); assert(false);

View File

@ -182,7 +182,8 @@ typedef enum {
TRI_AQL_NODE_REFERENCE, TRI_AQL_NODE_REFERENCE,
TRI_AQL_NODE_ATTRIBUTE, TRI_AQL_NODE_ATTRIBUTE,
TRI_AQL_NODE_PARAMETER, TRI_AQL_NODE_PARAMETER,
TRI_AQL_NODE_FCALL TRI_AQL_NODE_FCALL,
TRI_AQL_NODE_FCALL_USER
} }
TRI_aql_node_type_e; TRI_aql_node_type_e;

View File

@ -148,9 +148,13 @@ static TRI_aql_node_t* DumpNode (TRI_aql_statement_walker_t* const walker,
case TRI_AQL_NODE_ATTRIBUTE_ACCESS: case TRI_AQL_NODE_ATTRIBUTE_ACCESS:
DumpString(state, node); DumpString(state, node);
break; break;
case TRI_AQL_NODE_FCALL: case TRI_AQL_NODE_FCALL:
printf("name: %s\n", TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node))); printf("name: %s\n", TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node)));
break; break;
case TRI_AQL_NODE_FCALL_USER:
printf("name: %s\n", TRI_AQL_NODE_STRING(node));
break;
case TRI_AQL_NODE_SORT_ELEMENT: case TRI_AQL_NODE_SORT_ELEMENT:
PrintIndent(state); PrintIndent(state);

View File

@ -29,6 +29,8 @@
#include "Basics/ConditionLocker.h" #include "Basics/ConditionLocker.h"
#include "Basics/ReadLocker.h" #include "Basics/ReadLocker.h"
#include "Basics/MutexLocker.h"
#include "Basics/Mutex.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "Basics/WriteLocker.h" #include "Basics/WriteLocker.h"
#include "Logger/Logger.h" #include "Logger/Logger.h"
@ -121,6 +123,8 @@ namespace {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::V8Context::addGlobalContextMethod (string const& method) { void ApplicationV8::V8Context::addGlobalContextMethod (string const& method) {
MUTEX_LOCKER(_globalMethodsLock);
_globalMethods.push_back(method); _globalMethods.push_back(method);
} }
@ -130,6 +134,8 @@ void ApplicationV8::V8Context::addGlobalContextMethod (string const& method) {
void ApplicationV8::V8Context::handleGlobalContextMethods () { void ApplicationV8::V8Context::handleGlobalContextMethods () {
v8::HandleScope scope; v8::HandleScope scope;
MUTEX_LOCKER(_globalMethodsLock);
for (vector<string>::iterator i = _globalMethods.begin(); i != _globalMethods.end(); ++i) { for (vector<string>::iterator i = _globalMethods.begin(); i != _globalMethods.end(); ++i) {
string const& func = *i; string const& func = *i;
@ -278,6 +284,7 @@ ApplicationV8::V8Context* ApplicationV8::enterContext (bool initialise) {
context->_isolate->Enter(); context->_isolate->Enter();
context->_context->Enter(); context->_context->Enter();
LOGGER_TRACE("entering V8 context " << context->_id);
context->handleGlobalContextMethods(); context->handleGlobalContextMethods();
if (_developmentMode && ! initialise) { if (_developmentMode && ! initialise) {
@ -300,6 +307,7 @@ void ApplicationV8::exitContext (V8Context* context) {
V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread); V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
assert(gc != 0); assert(gc != 0);
LOGGER_TRACE("leaving V8 context " << context->_id);
double lastGc = gc->getLastGcStamp(); double lastGc = gc->getLastGcStamp();
CONDITION_LOCKER(guard, _contextCondition); CONDITION_LOCKER(guard, _contextCondition);
@ -337,24 +345,8 @@ void ApplicationV8::exitContext (V8Context* context) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::addGlobalContextMethod (string const& method) { void ApplicationV8::addGlobalContextMethod (string const& method) {
CONDITION_LOCKER(guard, _contextCondition); for (size_t i = 0; i < _nrInstances; ++i) {
_contexts[i]->addGlobalContextMethod(method);
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);
} }
} }

View File

@ -129,6 +129,12 @@ namespace triagens {
void handleGlobalContextMethods (); void handleGlobalContextMethods ();
////////////////////////////////////////////////////////////////////////////////
/// @brief mutex to protect _globalMethods
////////////////////////////////////////////////////////////////////////////////
basics::Mutex _globalMethodsLock;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief open global methods /// @brief open global methods
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -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 /// This function constructs multiple rows at once and should be preferred over
/// hasNext()...next() when iterating over bigger result sets /// 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; v8::HandleScope scope;
if (argv.Length() != 0) { if (argv.Length() != 0) {
TRI_V8_EXCEPTION_USAGE(scope, "getRows()"); TRI_V8_EXCEPTION_USAGE(scope, "toArray()");
} }
TRI_vocbase_t* vocbase = GetContextVocBase(); 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); 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 /// @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, "id", JS_IdGeneralCursor);
TRI_AddProtoMethodVocbase(pt, "next", JS_NextGeneralCursor); TRI_AddProtoMethodVocbase(pt, "next", JS_NextGeneralCursor);
TRI_AddProtoMethodVocbase(pt, "persist", JS_PersistGeneralCursor); TRI_AddProtoMethodVocbase(pt, "persist", JS_PersistGeneralCursor);
TRI_AddProtoMethodVocbase(pt, "toArray", JS_ToArrayGeneralCursor);
TRI_AddProtoMethodVocbase(pt, "unuse", JS_UnuseGeneralCursor); TRI_AddProtoMethodVocbase(pt, "unuse", JS_UnuseGeneralCursor);
rt = ft->InstanceTemplate(); rt = ft->InstanceTemplate();

View File

@ -220,7 +220,7 @@ static bool Compactifier (TRI_df_marker_t const* marker, void* data, TRI_datafil
TRI_document_collection_t* doc; TRI_document_collection_t* doc;
TRI_primary_collection_t* primary; TRI_primary_collection_t* primary;
TRI_voc_fid_t fid; TRI_voc_fid_t fid;
TRI_voc_tid_t tid; // TRI_voc_tid_t tid;
int res; int res;
doc = data; 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; TRI_doc_document_key_marker_t const* d = (TRI_doc_document_key_marker_t const*) marker;
bool deleted; bool deleted;
tid = d->_tid; // tid = d->_tid;
// check if the document is still active // check if the document is still active
TRI_READ_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); 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 // deletion
else if (marker->_type == TRI_DOC_MARKER_KEY_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; 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 // write to compactor files
res = CopyDocument(doc, marker, &result, &fid); res = CopyDocument(doc, marker, &result, &fid);

View File

@ -467,7 +467,10 @@ typedef struct TRI_doc_begin_transaction_marker_s {
TRI_df_marker_t base; TRI_df_marker_t base;
TRI_voc_tid_t _tid; 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; TRI_doc_begin_transaction_marker_t;

View File

@ -110,6 +110,9 @@
"ERROR_QUERY_FAIL_CALLED" : { "code" : 1569, "message" : "FAIL(%s) called" }, "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_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_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_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" },
"ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" }, "ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" },
"ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" }, "ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" },

View File

@ -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 /// @brief flushes the module cache of the server
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -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 /// @fn JSF_GET_admin_routing_reloads
/// @brief reloads the routing information /// @brief reloads the routing information

View File

@ -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 /// @brief flushes the module cache of the server
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -110,6 +110,9 @@
"ERROR_QUERY_FAIL_CALLED" : { "code" : 1569, "message" : "FAIL(%s) called" }, "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_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_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_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" },
"ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" }, "ERROR_TRANSACTION_INCOMPLETE" : { "code" : 1650, "message" : "transaction definition is incomplete" },
"ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" }, "ERROR_TRANSACTION_INVALID_STATE" : { "code" : 1651, "message" : "invalid transaction state" },

View File

@ -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:

View File

@ -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:

View File

@ -164,6 +164,32 @@ function CollectionVolatileSuite () {
internal.wait(4); internal.wait(4);
assertEqual(true, c.properties().isVolatile); assertEqual(true, c.properties().isVolatile);
assertEqual(0, c.count()); 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());
} }
}; };

View File

@ -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 /// @brief executes a string in all V8 contexts
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -2022,7 +2022,10 @@ exports.HTTP_NOT_FOUND = 404;
exports.HTTP_METHOD_NOT_ALLOWED = 405; exports.HTTP_METHOD_NOT_ALLOWED = 405;
exports.HTTP_CONFLICT = 409; exports.HTTP_CONFLICT = 409;
exports.HTTP_PRECONDITION_FAILED = 412; 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_UNPROCESSABLE_ENTIT = 422;
exports.HTTP_HEADER_TOO_LARGE = 431;
// HTTP 5xx // HTTP 5xx
exports.HTTP_SERVER_ERROR = 500; exports.HTTP_SERVER_ERROR = 500;

View File

@ -34,8 +34,6 @@ var INTERNAL = require("internal");
var TRAVERSAL = require("org/arangodb/graph/traversal"); var TRAVERSAL = require("org/arangodb/graph/traversal");
var ArangoError = require("org/arangodb/arango-error").ArangoError; var ArangoError = require("org/arangodb/arango-error").ArangoError;
var RegexCache = { 'i' : { }, '' : { } };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --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 /// @brief type weight used for sorting and comparing
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -209,6 +219,44 @@ function CLONE (obj) {
return copy; 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 /// @brief get the sort type of an operand
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -317,6 +365,20 @@ function FCALL (name, parameters) {
return name.apply(null, 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 /// @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 // --SECTION-- MODULE EXPORTS
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -3230,6 +3357,7 @@ function GRAPH_EDGES (edgeCollection,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
exports.FCALL = FCALL; exports.FCALL = FCALL;
exports.FCALL_USER = FCALL_USER;
exports.KEYS = KEYS; exports.KEYS = KEYS;
exports.GET_INDEX = GET_INDEX; exports.GET_INDEX = GET_INDEX;
exports.DOCUMENT_MEMBER = DOCUMENT_MEMBER; exports.DOCUMENT_MEMBER = DOCUMENT_MEMBER;
@ -3331,10 +3459,16 @@ exports.MATCHES = MATCHES;
exports.PASSTHRU = PASSTHRU; exports.PASSTHRU = PASSTHRU;
exports.FAIL = FAIL; exports.FAIL = FAIL;
exports.reload = reloadUserFunctions;
// initialise the query engine
resetEngine();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @} /// @}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -59,7 +59,10 @@ var Application,
/// a constraint and a method. For example: /// a constraint and a method. For example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// internal.createUrlObject('/lecker/gans', null, 'get'); /// internal.createUrlObject('/lecker/gans', null, 'get');
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
internal.createUrlObject = function (url, constraint, method) { 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 /// * **The Template Collection:** More information in the template section
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app = new Application({ /// app = new Application({
/// urlPrefix: "/wiese", /// urlPrefix: "/wiese",
/// templateCollection: "my_templates" /// templateCollection: "my_templates"
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Application = function (options) { Application = function (options) {
@ -170,9 +176,12 @@ _.extend(Application.prototype, {
/// object). /// object).
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.handleRequest("get", "/gaense", function (req, res) { /// app.handleRequest("get", "/gaense", function (req, res) {
/// //handle the request /// //handle the request
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
handleRequest: function (method, route, callback) { handleRequest: function (method, route, callback) {
@ -216,9 +225,12 @@ _.extend(Application.prototype, {
/// See above for the arguments you can give. An example: /// See above for the arguments you can give. An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.get('/gaense/stall', function (req, res) { /// app.get('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
get: function (route, callback) { get: function (route, callback) {
'use strict'; 'use strict';
@ -233,9 +245,12 @@ _.extend(Application.prototype, {
/// See above for the arguments you can give. An example: /// See above for the arguments you can give. An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.post('/gaense/stall', function (req, res) { /// app.post('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
post: function (route, callback) { post: function (route, callback) {
'use strict'; 'use strict';
@ -250,9 +265,12 @@ _.extend(Application.prototype, {
/// See above for the arguments you can give. An example: /// See above for the arguments you can give. An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.put('/gaense/stall', function (req, res) { /// app.put('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
put: function (route, callback) { put: function (route, callback) {
'use strict'; 'use strict';
@ -267,9 +285,12 @@ _.extend(Application.prototype, {
/// See above for the arguments you can give. An example: /// See above for the arguments you can give. An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.patch('/gaense/stall', function (req, res) { /// app.patch('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
patch: function (route, callback) { patch: function (route, callback) {
'use strict'; 'use strict';
@ -288,6 +309,8 @@ _.extend(Application.prototype, {
/// for this very reason. /// for this very reason.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app['delete']('/gaense/stall', function (req, res) { /// app['delete']('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
@ -295,6 +318,7 @@ _.extend(Application.prototype, {
/// app.del('/gaense/stall', function (req, res) { /// app.del('/gaense/stall', function (req, res) {
/// // Take this request and deal with it! /// // Take this request and deal with it!
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
'delete': function (route, callback) { 'delete': function (route, callback) {
@ -319,9 +343,12 @@ _.extend(Application.prototype, {
/// An example: /// An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.before('/high/way', function(req, res) { /// app.before('/high/way', function(req, res) {
/// //Do some crazy request logging /// //Do some crazy request logging
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
before: function (path, func) { before: function (path, func) {
@ -350,9 +377,12 @@ _.extend(Application.prototype, {
/// An example: /// An example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.after('/high/way', function(req, res) { /// app.after('/high/way', function(req, res) {
/// //Do some crazy response logging /// //Do some crazy response logging
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
after: function (path, func) { after: function (path, func) {
@ -381,9 +411,12 @@ _.extend(Application.prototype, {
/// blocks. /// blocks.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.helper("link_to", function (identifier) { /// app.helper("link_to", function (identifier) {
/// return urlRepository[identifier]; /// return urlRepository[identifier];
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
helper: function (name, func) { helper: function (name, func) {
@ -400,7 +433,10 @@ _.extend(Application.prototype, {
/// This is a shortcut to add the middleware to your application: /// This is a shortcut to add the middleware to your application:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.accepts(["json"], "json"); /// app.accepts(["json"], "json");
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
accepts: function (allowedFormats, defaultFormat) { accepts: function (allowedFormats, defaultFormat) {
@ -446,12 +482,15 @@ _.extend(RequestContext.prototype, {
/// You can also provide a description of this parameter. /// You can also provide a description of this parameter.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.get("/foxx/:id", function { /// app.get("/foxx/:id", function {
/// // Do something /// // Do something
/// }).pathParam("id", { /// }).pathParam("id", {
/// description: "Id of the Foxx", /// description: "Id of the Foxx",
/// dataType: "int" /// dataType: "int"
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
pathParam: function (paramName, attributes) { pathParam: function (paramName, attributes) {
@ -489,6 +528,8 @@ _.extend(RequestContext.prototype, {
/// if you can provide the parameter multiple times. /// if you can provide the parameter multiple times.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// app.get("/foxx", function { /// app.get("/foxx", function {
/// // Do something /// // Do something
/// }).queryParam("id", { /// }).queryParam("id", {
@ -497,6 +538,7 @@ _.extend(RequestContext.prototype, {
/// required: true, /// required: true,
/// allowMultiple: false /// allowMultiple: false
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
queryParam: function (paramName, attributes) { queryParam: function (paramName, attributes) {
@ -632,7 +674,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
/// Set the status code of your response, for example: /// Set the status code of your response, for example:
/// ///
/// @EXAMPLES /// @EXAMPLES
/// response.status(404); ///
/// @code
/// response.status(404);
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
status: function (code) { status: function (code) {
this.responseCode = code; this.responseCode = code;
@ -645,6 +690,8 @@ BaseMiddleware = function (templateCollection, helperCollection) {
/// Set a header attribute, for example: /// Set a header attribute, for example:
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// response.set("Content-Length", 123); /// response.set("Content-Length", 123);
/// response.set("Content-Type", "text/plain"); /// response.set("Content-Type", "text/plain");
/// ///
@ -654,6 +701,7 @@ BaseMiddleware = function (templateCollection, helperCollection) {
/// "Content-Length": "123", /// "Content-Length": "123",
/// "Content-Type": "text/plain" /// "Content-Type": "text/plain"
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
set: function (key, value) { set: function (key, value) {
@ -683,7 +731,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
/// JSON encoded object you provided. /// JSON encoded object you provided.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// response.json({'born': 'December 12, 1915'}); /// response.json({'born': 'December 12, 1915'});
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
json: function (obj) { json: function (obj) {
@ -725,7 +776,10 @@ BaseMiddleware = function (templateCollection, helperCollection) {
/// ViewHelper section. /// ViewHelper section.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// response.render("high/way", {username: 'Application'}) /// response.render("high/way", {username: 'Application'})
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
render: function (templatePath, data) { render: function (templatePath, data) {
var template; var template;
@ -853,9 +907,12 @@ FormatMiddleware = function (allowedFormats, defaultFormat) {
/// as an object. /// as an object.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// instance = new Model({ /// instance = new Model({
/// a: 1 /// a: 1
/// }); /// });
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Model = function (attributes) { Model = function (attributes) {
@ -871,11 +928,14 @@ _.extend(Model.prototype, {
/// ///
/// Get the value of an attribute /// Get the value of an attribute
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// instance = new Model({ /// instance = new Model({
/// a: 1 /// a: 1
/// }); /// });
/// ///
/// instance.get("a"); /// instance.get("a");
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
get: function (attributeName) { get: function (attributeName) {
@ -888,11 +948,14 @@ _.extend(Model.prototype, {
/// ///
/// Set the value of an attribute /// Set the value of an attribute
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// instance = new Model({ /// instance = new Model({
/// a: 1 /// a: 1
/// }); /// });
/// ///
/// instance.set("a", 2); /// instance.set("a", 2);
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
set: function (attributeName, value) { 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. /// Returns true if the attribute is set to a non-null or non-undefined value.
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// instance = new Model({ /// instance = new Model({
/// a: 1 /// a: 1
/// }); /// });
/// ///
/// instance.has("a"); //=> true /// instance.has("a"); //=> true
/// instance.has("b"); //=> false /// instance.has("b"); //=> false
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
has: function (attributeName) { 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. /// If you initialize a model, you can give it initial data as an object.
/// ///
/// @EXAMPLES /// @EXAMPLES
///
/// @code
/// instance = new Repository(prefix, collection, modelPrototype); /// instance = new Repository(prefix, collection, modelPrototype);
/// @endcode
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Repository = function (prefix, collection, modelPrototype) { Repository = function (prefix, collection, modelPrototype) {

View File

@ -344,6 +344,11 @@
return true; 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 // loop through all tasks and execute them
console.log("Found " + allTasks.length + " defined task(s), " console.log("Found " + allTasks.length + " defined task(s), "

View File

@ -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_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." 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 ## ArangoDB cursor errors
################################################################################ ################################################################################

View File

@ -106,6 +106,9 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_QUERY_FAIL_CALLED, "FAIL(%s) called"); 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_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_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_CURSOR_NOT_FOUND, "cursor not found");
REG_ERROR(ERROR_TRANSACTION_INCOMPLETE, "transaction definition is incomplete"); REG_ERROR(ERROR_TRANSACTION_INCOMPLETE, "transaction definition is incomplete");
REG_ERROR(ERROR_TRANSACTION_INVALID_STATE, "invalid transaction state"); REG_ERROR(ERROR_TRANSACTION_INVALID_STATE, "invalid transaction state");

View File

@ -230,6 +230,12 @@ extern "C" {
/// - 1571: @LIT{no suitable fulltext index found for fulltext query on '\%s'} /// - 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 /// Will be raised when a fulltext query is performed on a collection without
/// a suitable fulltext index. /// 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} /// - 1600: @LIT{cursor not found}
/// Will be raised when a cursor is requested via its id but a cursor with /// Will be raised when a cursor is requested via its id but a cursor with
/// that id cannot be found. /// that id cannot be found.
@ -1372,6 +1378,36 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_QUERY_FULLTEXT_INDEX_MISSING (1571) #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 /// @brief 1600: ERROR_CURSOR_NOT_FOUND
/// ///

View File

@ -51,7 +51,6 @@ using namespace std;
string HttpResponse::responseString (HttpResponseCode code) { string HttpResponse::responseString (HttpResponseCode code) {
switch (code) { switch (code) {
// Success 2xx // Success 2xx
case OK: return "200 OK"; case OK: return "200 OK";
case CREATED: return "201 Created"; case CREATED: return "201 Created";
@ -77,6 +76,7 @@ string HttpResponse::responseString (HttpResponseCode code) {
case LENGTH_REQUIRED: return "411 Length Required"; case LENGTH_REQUIRED: return "411 Length Required";
case PRECONDITION_FAILED: return "412 Precondition Failed"; case PRECONDITION_FAILED: return "412 Precondition Failed";
case ENTITY_TOO_LARGE: return "413 Request Entity Too Large"; 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 UNPROCESSABLE_ENTITY: return "422 Unprocessable Entity";
case HEADER_TOO_LARGE: return "431 Request Header Fields Too Large"; 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 405: return METHOD_NOT_ALLOWED;
case 409: return CONFLICT; case 409: return CONFLICT;
case 412: return PRECONDITION_FAILED; case 412: return PRECONDITION_FAILED;
case 418: return I_AM_A_TEAPOT;
case 422: return UNPROCESSABLE_ENTITY; case 422: return UNPROCESSABLE_ENTITY;
case 500: return SERVER_ERROR; case 500: return SERVER_ERROR;

View File

@ -100,6 +100,7 @@ namespace triagens {
LENGTH_REQUIRED = 411, LENGTH_REQUIRED = 411,
PRECONDITION_FAILED = 412, PRECONDITION_FAILED = 412,
ENTITY_TOO_LARGE = 413, ENTITY_TOO_LARGE = 413,
I_AM_A_TEAPOT = 418,
UNPROCESSABLE_ENTITY = 422, UNPROCESSABLE_ENTITY = 422,
HEADER_TOO_LARGE = 431, HEADER_TOO_LARGE = 431,