mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
d79c9f928c
|
@ -644,27 +644,48 @@ AstNode* Ast::createNodeArrayElement (char const* attributeName,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* Ast::createNodeFunctionCall (char const* functionName,
|
AstNode* Ast::createNodeFunctionCall (char const* functionName,
|
||||||
AstNode const* parameters) {
|
AstNode const* arguments) {
|
||||||
if (functionName == nullptr) {
|
if (functionName == nullptr) {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const normalizedName = normalizeFunctionName(functionName);
|
auto normalized = normalizeFunctionName(functionName);
|
||||||
char* fname = _query->registerString(normalizedName.c_str(), normalizedName.size(), false);
|
|
||||||
|
|
||||||
AstNode* node;
|
AstNode* node;
|
||||||
|
|
||||||
if (normalizedName[0] == '_') {
|
if (normalized.second) {
|
||||||
// built-in function
|
// built-in function
|
||||||
node = createNode(NODE_TYPE_FCALL);
|
node = createNode(NODE_TYPE_FCALL);
|
||||||
|
// register a pointer to the function
|
||||||
|
auto func = _query->executor()->getFunctionByName(normalized.first);
|
||||||
|
|
||||||
|
TRI_ASSERT(func != nullptr);
|
||||||
|
node->setData(static_cast<void const*>(func));
|
||||||
|
|
||||||
|
TRI_ASSERT(arguments != nullptr);
|
||||||
|
TRI_ASSERT(arguments->type == NODE_TYPE_LIST);
|
||||||
|
|
||||||
|
// validate number of function call arguments
|
||||||
|
size_t const n = arguments->numMembers();
|
||||||
|
|
||||||
|
auto numExpectedArguments = func->numArguments();
|
||||||
|
if (n < numExpectedArguments.first || n > numExpectedArguments.second) {
|
||||||
|
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH,
|
||||||
|
functionName,
|
||||||
|
static_cast<int>(numExpectedArguments.first),
|
||||||
|
static_cast<int>(numExpectedArguments.second));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// user-defined function
|
// user-defined function
|
||||||
node = createNode(NODE_TYPE_FCALL_USER);
|
node = createNode(NODE_TYPE_FCALL_USER);
|
||||||
|
// register the function name
|
||||||
|
char* fname = _query->registerString(normalized.first.c_str(), normalized.first.size(), false);
|
||||||
|
node->setStringValue(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
node->setStringValue(fname);
|
node->addMember(arguments);
|
||||||
node->addMember(parameters);
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -810,6 +831,11 @@ void Ast::optimize () {
|
||||||
return optimizeTernaryOperator(node);
|
return optimizeTernaryOperator(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call to built-in function
|
||||||
|
if (node->type == NODE_TYPE_FCALL) {
|
||||||
|
return optimizeFunctionCall(node);
|
||||||
|
}
|
||||||
|
|
||||||
// reference to a variable
|
// reference to a variable
|
||||||
if (node->type == NODE_TYPE_REFERENCE) {
|
if (node->type == NODE_TYPE_REFERENCE) {
|
||||||
return optimizeReference(node);
|
return optimizeReference(node);
|
||||||
|
@ -875,10 +901,10 @@ std::unordered_set<Variable*> Ast::getReferencedVariables (AstNode const* node)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief executes a comparison function
|
/// @brief executes an expression with constant parameters
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* Ast::executeConstComparison (AstNode const* node) {
|
AstNode* Ast::executeConstExpression (AstNode const* node) {
|
||||||
TRI_json_t* result = _query->executor()->executeExpression(node);
|
TRI_json_t* result = _query->executor()->executeExpression(node);
|
||||||
|
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
|
@ -1105,7 +1131,7 @@ AstNode* Ast::optimizeBinaryOperatorRelational (AstNode* node) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return executeConstComparison(node);
|
return executeConstExpression(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1229,6 +1255,31 @@ AstNode* Ast::optimizeTernaryOperator (AstNode* node) {
|
||||||
return falsePart;
|
return falsePart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief optimizes a call to a built-in function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* Ast::optimizeFunctionCall (AstNode* node) {
|
||||||
|
TRI_ASSERT(node != nullptr);
|
||||||
|
TRI_ASSERT(node->type == NODE_TYPE_FCALL);
|
||||||
|
TRI_ASSERT(node->numMembers() == 1);
|
||||||
|
|
||||||
|
auto func = static_cast<Function*>(node->getData());
|
||||||
|
TRI_ASSERT(func != nullptr);
|
||||||
|
|
||||||
|
if (! func->isDeterministic) {
|
||||||
|
// non-deterministic function
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! node->getMember(0)->isConstant()) {
|
||||||
|
// arguments to function call are not constant
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return executeConstExpression(node);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief optimizes a reference to a variable
|
/// @brief optimizes a reference to a variable
|
||||||
/// references are replaced with constants if possible
|
/// references are replaced with constants if possible
|
||||||
|
@ -1474,7 +1525,7 @@ void Ast::traverse (AstNode const* node,
|
||||||
/// @brief normalize a function name
|
/// @brief normalize a function name
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::string Ast::normalizeFunctionName (char const* name) {
|
std::pair<std::string, bool> Ast::normalizeFunctionName (char const* name) {
|
||||||
TRI_ASSERT(name != nullptr);
|
TRI_ASSERT(name != nullptr);
|
||||||
|
|
||||||
char* upperName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, name);
|
char* upperName = TRI_UpperAsciiStringZ(TRI_UNKNOWN_MEM_ZONE, name);
|
||||||
|
@ -1489,10 +1540,11 @@ std::string Ast::normalizeFunctionName (char const* name) {
|
||||||
|
|
||||||
if (functionName.find(':') == std::string::npos) {
|
if (functionName.find(':') == std::string::npos) {
|
||||||
// prepend default namespace for internal functions
|
// prepend default namespace for internal functions
|
||||||
functionName = "_AQL:" + functionName;
|
return std::make_pair(functionName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return functionName;
|
// user-defined function
|
||||||
|
return std::make_pair(functionName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -499,10 +499,10 @@ namespace triagens {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief executes a comparison function
|
/// @brief executes an expression with constant parameters
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* executeConstComparison (AstNode const*);
|
AstNode* executeConstExpression (AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief optimizes a FILTER node
|
/// @brief optimizes a FILTER node
|
||||||
|
@ -548,6 +548,12 @@ namespace triagens {
|
||||||
|
|
||||||
AstNode* optimizeTernaryOperator (AstNode*);
|
AstNode* optimizeTernaryOperator (AstNode*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief optimizes a call to a built-in function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* optimizeFunctionCall (AstNode*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief optimizes a reference to a variable
|
/// @brief optimizes a reference to a variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -599,7 +605,7 @@ namespace triagens {
|
||||||
/// @brief normalize a function name
|
/// @brief normalize a function name
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::string normalizeFunctionName (char const*);
|
std::pair<std::string, bool> normalizeFunctionName (char const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create a node of the specified type
|
/// @brief create a node of the specified type
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "Aql/AstNode.h"
|
#include "Aql/AstNode.h"
|
||||||
|
#include "Aql/Function.h"
|
||||||
#include "Aql/Scopes.h"
|
#include "Aql/Scopes.h"
|
||||||
#include "Basics/StringBuffer.h"
|
#include "Basics/StringBuffer.h"
|
||||||
|
|
||||||
|
@ -77,12 +78,16 @@ TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone) const {
|
||||||
if (type == NODE_TYPE_COLLECTION ||
|
if (type == NODE_TYPE_COLLECTION ||
|
||||||
type == NODE_TYPE_PARAMETER ||
|
type == NODE_TYPE_PARAMETER ||
|
||||||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||||
type == NODE_TYPE_FCALL ||
|
|
||||||
type == NODE_TYPE_FCALL_USER) {
|
type == NODE_TYPE_FCALL_USER) {
|
||||||
// dump "name" of node
|
// dump "name" of node
|
||||||
TRI_Insert3ArrayJson(zone, node, "name", TRI_CreateStringCopyJson(zone, getStringValue()));
|
TRI_Insert3ArrayJson(zone, node, "name", TRI_CreateStringCopyJson(zone, getStringValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_FCALL) {
|
||||||
|
auto func = static_cast<Function*>(getData());
|
||||||
|
TRI_Insert3ArrayJson(zone, node, "name", TRI_CreateStringCopyJson(zone, func->name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
if (type == NODE_TYPE_VALUE) {
|
if (type == NODE_TYPE_VALUE) {
|
||||||
// dump value of "value" node
|
// dump value of "value" node
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
|
|
|
@ -366,6 +366,14 @@ namespace triagens {
|
||||||
value.value._data = v;
|
value.value._data = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief set the data value of a node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline void setData (void const* v) {
|
||||||
|
value.value._data = const_cast<void*>(v);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return the type name of a node
|
/// @brief return the type name of a node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief Aql, built-in function
|
||||||
|
///
|
||||||
|
/// @file
|
||||||
|
///
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ARANGODB_AQL_FUNCTION_H
|
||||||
|
#define ARANGODB_AQL_FUNCTION_H 1
|
||||||
|
|
||||||
|
#include "Basics/Common.h"
|
||||||
|
|
||||||
|
namespace triagens {
|
||||||
|
namespace aql {
|
||||||
|
|
||||||
|
struct Function {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors / destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Function () = delete;
|
||||||
|
|
||||||
|
Function (std::string const& name,
|
||||||
|
std::string const& arguments,
|
||||||
|
bool isDeterministic)
|
||||||
|
: name(name),
|
||||||
|
arguments(arguments),
|
||||||
|
isDeterministic(isDeterministic) {
|
||||||
|
|
||||||
|
initArguments();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Function () {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief checks if the function has been deprecated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isDeprecated () const {
|
||||||
|
// currently there are no deprecated functions
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the number of required arguments
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline std::pair<size_t, size_t> numArguments () const {
|
||||||
|
return std::make_pair(minRequiredArguments, maxRequiredArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief parse the argument list and set the minimum and maximum number of
|
||||||
|
/// arguments
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void initArguments () {
|
||||||
|
minRequiredArguments = maxRequiredArguments = 0;
|
||||||
|
|
||||||
|
// setup some parsing state
|
||||||
|
bool inOptional = false;
|
||||||
|
bool foundArg = false;
|
||||||
|
|
||||||
|
char const* p = arguments.c_str();
|
||||||
|
while (true) {
|
||||||
|
char const c = *p++;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\0':
|
||||||
|
// end of argument list
|
||||||
|
if (foundArg) {
|
||||||
|
if (! inOptional) {
|
||||||
|
++minRequiredArguments;
|
||||||
|
}
|
||||||
|
++maxRequiredArguments;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
// beginning of optional arguments
|
||||||
|
TRI_ASSERT(! inOptional);
|
||||||
|
if (foundArg) {
|
||||||
|
++minRequiredArguments;
|
||||||
|
++maxRequiredArguments;
|
||||||
|
}
|
||||||
|
inOptional = true;
|
||||||
|
foundArg = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
// next argument
|
||||||
|
TRI_ASSERT(foundArg);
|
||||||
|
|
||||||
|
if (! inOptional) {
|
||||||
|
++minRequiredArguments;
|
||||||
|
}
|
||||||
|
++maxRequiredArguments;
|
||||||
|
foundArg = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
// repeated optional argument
|
||||||
|
TRI_ASSERT(inOptional);
|
||||||
|
maxRequiredArguments = MaxArguments;
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
foundArg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief function name
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string const name;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief function arguments
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string const arguments;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the function is deterministic (i.e. its results are
|
||||||
|
/// identical when called repeatedly with the same input values)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool const isDeterministic;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief minimum number of required arguments
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t minRequiredArguments;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief maximum number of required arguments
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t maxRequiredArguments;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief maximum number of function arguments that can be used
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static size_t const MaxArguments = 1024;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- END-OF-FILE
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||||
|
// End:
|
|
@ -163,7 +163,7 @@ void Query::registerError (int code,
|
||||||
THROW_ARANGO_EXCEPTION(code);
|
THROW_ARANGO_EXCEPTION(code);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
THROW_ARANGO_EXCEPTION_STRING(code, details);
|
THROW_ARANGO_EXCEPTION_PARAMS(code, details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ void Scopes::addVariable (Variable* variable) {
|
||||||
|
|
||||||
if (scope->existsVariable(variable->name)) {
|
if (scope->existsVariable(variable->name)) {
|
||||||
// duplicate variable name
|
// duplicate variable name
|
||||||
THROW_ARANGO_EXCEPTION_STRING(TRI_ERROR_QUERY_VARIABLE_REDECLARED, variable->name);
|
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_VARIABLE_REDECLARED, variable->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,14 @@
|
||||||
using namespace triagens::aql;
|
using namespace triagens::aql;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- function names used in execution
|
// --SECTION-- static initialization
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
std::unordered_map<int, std::string> const V8Executor::FunctionNames{
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief internal functions used in execution
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::unordered_map<int, std::string const> const V8Executor::InternalFunctionNames{
|
||||||
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_PLUS), "UNARY_PLUS" },
|
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_PLUS), "UNARY_PLUS" },
|
||||||
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_MINUS), "UNARY_MINUS" },
|
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_MINUS), "UNARY_MINUS" },
|
||||||
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_NOT), "LOGICAL_NOT" },
|
{ static_cast<int>(NODE_TYPE_OPERATOR_UNARY_NOT), "LOGICAL_NOT" },
|
||||||
|
@ -63,6 +67,156 @@ std::unordered_map<int, std::string> const V8Executor::FunctionNames{
|
||||||
{ static_cast<int>(NODE_TYPE_OPERATOR_TERNARY), "TERNARY_OPERATOR_FN" }
|
{ static_cast<int>(NODE_TYPE_OPERATOR_TERNARY), "TERNARY_OPERATOR_FN" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief user-accessible functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Function const> const V8Executor::FunctionNames{
|
||||||
|
// meanings of the symbols in the function arguments list
|
||||||
|
// ------------------------------------------------------
|
||||||
|
//
|
||||||
|
// . = argument of any type (except collection)
|
||||||
|
// c = collection name, will be converted into list with documents
|
||||||
|
// h = collection name, will be converted into string
|
||||||
|
// z = null
|
||||||
|
// b = bool
|
||||||
|
// n = number
|
||||||
|
// s = string
|
||||||
|
// p = primitive
|
||||||
|
// l = list
|
||||||
|
// a = (hash) array/document
|
||||||
|
// r = regex (a string with a special format). note: the regex type is mutually exclusive with all other types
|
||||||
|
|
||||||
|
// type check functions
|
||||||
|
{ "IS_NULL", Function("IS_NULL", ".", true) },
|
||||||
|
{ "IS_BOOL", Function("IS_BOOL", ".", true) },
|
||||||
|
{ "IS_NUMBER", Function("IS_NUMBER", ".", true) },
|
||||||
|
{ "IS_STRING", Function("IS_STRING", ".", true) },
|
||||||
|
{ "IS_LIST", Function("IS_LIST", ".", true) },
|
||||||
|
{ "IS_DOCUMENT", Function("IS_DOCUMENT", ".", true) },
|
||||||
|
|
||||||
|
// type cast functions
|
||||||
|
{ "TO_NUMBER", Function("CAST_NUMBER", ".", true) },
|
||||||
|
{ "TO_STRING", Function("CAST_STRING", ".", true) },
|
||||||
|
{ "TO_BOOL", Function("CAST_BOOL", ".", true) },
|
||||||
|
{ "TO_LIST", Function("CAST_LIST", ".", true) },
|
||||||
|
|
||||||
|
// string functions
|
||||||
|
{ "CONCAT", Function("STRING_CONCAT", "sz,sz|+", true) },
|
||||||
|
{ "CONCAT_SEPARATOR", Function("STRING_CONCAT_SEPARATOR", "s,sz,sz|+", true) },
|
||||||
|
{ "CHAR_LENGTH", Function("CHAR_LENGTH", "s", true) },
|
||||||
|
{ "LOWER", Function("STRING_LOWER", "s", true) },
|
||||||
|
{ "UPPER", Function("STRING_UPPER", "s", true) },
|
||||||
|
{ "SUBSTRING", Function("STRING_SUBSTRING", "s,n|n", true) },
|
||||||
|
{ "CONTAINS", Function("STRING_CONTAINS", "s,s|b", true) },
|
||||||
|
{ "LIKE", Function("STRING_LIKE", "s,r|b", true) },
|
||||||
|
{ "LEFT", Function("STRING_LEFT", "s,n", true) },
|
||||||
|
{ "RIGHT", Function("STRING_RIGHT", "s,n", true) },
|
||||||
|
{ "TRIM", Function("STRING_TRIM", "s|n", true) },
|
||||||
|
|
||||||
|
// numeric functions
|
||||||
|
{ "FLOOR", Function("NUMBER_FLOOR", "n", true) },
|
||||||
|
{ "CEIL", Function("NUMBER_CEIL", "n", true) },
|
||||||
|
{ "ROUND", Function("NUMBER_ROUND", "n", true) },
|
||||||
|
{ "ABS", Function("NUMBER_ABS", "n", true) },
|
||||||
|
{ "RAND", Function("NUMBER_RAND", "", false) },
|
||||||
|
{ "SQRT", Function("NUMBER_SQRT", "n", true) },
|
||||||
|
|
||||||
|
// list functions
|
||||||
|
{ "RANGE", Function("RANGE", "n,n|n", true) },
|
||||||
|
{ "UNION", Function("UNION", "l,l|+",true) },
|
||||||
|
{ "UNION_DISTINCT", Function("UNION_DISTINCT", "l,l|+", true) },
|
||||||
|
{ "MINUS", Function("MINUS", "l,l|+", true) },
|
||||||
|
{ "INTERSECTION", Function("INTERSECTION", "l,l|+", true) },
|
||||||
|
{ "FLATTEN", Function("FLATTEN", "l|n", true) },
|
||||||
|
{ "LENGTH", Function("LENGTH", "las", true) },
|
||||||
|
{ "MIN", Function("MIN", "l", true) },
|
||||||
|
{ "MAX", Function("MAX", "l", true) },
|
||||||
|
{ "SUM", Function("SUM", "l", true) },
|
||||||
|
{ "MEDIAN", Function("MEDIAN", "l", true) },
|
||||||
|
{ "AVERAGE", Function("AVERAGE", "l", true) },
|
||||||
|
{ "VARIANCE_SAMPLE", Function("VARIANCE_SAMPLE", "l", true) },
|
||||||
|
{ "VARIANCE_POPULATION", Function("VARIANCE_POPULATION", "l", true) },
|
||||||
|
{ "STDDEV_SAMPLE", Function("STDDEV_SAMPLE", "l", true) },
|
||||||
|
{ "STDDEV_POPULATION", Function("STDDEV_POPULATION", "l", true) },
|
||||||
|
{ "UNIQUE", Function("UNIQUE", "l", true) },
|
||||||
|
{ "SLICE", Function("SLICE", "l,n|n", true) },
|
||||||
|
{ "REVERSE", Function("REVERSE", "ls", true) }, // note: REVERSE() can be applied on strings, too
|
||||||
|
{ "FIRST", Function("FIRST", "l", true) },
|
||||||
|
{ "LAST", Function("LAST", "l", true) },
|
||||||
|
{ "NTH", Function("NTH", "l,n", true) },
|
||||||
|
{ "POSITION", Function("POSITION", "l,.|b", true) },
|
||||||
|
|
||||||
|
// document functions
|
||||||
|
{ "HAS", Function("HAS", "az,s", true) },
|
||||||
|
{ "ATTRIBUTES", Function("ATTRIBUTES", "a|b,b", true) },
|
||||||
|
{ "MERGE", Function("MERGE", "a,a|+", true) },
|
||||||
|
{ "MERGE_RECURSIVE", Function("MERGE_RECURSIVE", "a,a|+", true) },
|
||||||
|
{ "DOCUMENT", Function("DOCUMENT", "h.|.", true) },
|
||||||
|
{ "MATCHES", Function("MATCHES", ".,l|b", true) },
|
||||||
|
{ "UNSET", Function("UNSET", "a,sl|+", true) },
|
||||||
|
{ "KEEP", Function("KEEP", "a,sl|+", true) },
|
||||||
|
{ "TRANSLATE", Function("TRANSLATE", ".,a|.", true) },
|
||||||
|
|
||||||
|
// geo functions
|
||||||
|
{ "NEAR", Function("GEO_NEAR", "h,n,n|nz,s", false) },
|
||||||
|
{ "WITHIN", Function("GEO_WITHIN", "h,n,n,n|s", false) },
|
||||||
|
|
||||||
|
// fulltext functions
|
||||||
|
{ "FULLTEXT", Function("FULLTEXT", "h,s,s", false) },
|
||||||
|
|
||||||
|
// graph functions
|
||||||
|
{ "PATHS", Function("GRAPH_PATHS", "c,h|s,b", false )},
|
||||||
|
{ "GRAPH_PATHS", Function("GENERAL_GRAPH_PATHS", "s|a", false )},
|
||||||
|
{ "SHORTEST_PATH", Function("GRAPH_SHORTEST_PATH", "h,h,s,s,s|a", false )},
|
||||||
|
{ "GRAPH_SHORTEST_PATH", Function("GENERAL_GRAPH_SHORTEST_PATH", "s,als,als|a", false )},
|
||||||
|
{ "GRAPH_DISTANCE_TO", Function("GENERAL_GRAPH_DISTANCE_TO", "s,als,als|a", false )},
|
||||||
|
{ "TRAVERSAL", Function("GRAPH_TRAVERSAL", "h,h,s,s|a", false )},
|
||||||
|
{ "GRAPH_TRAVERSAL", Function("GENERAL_GRAPH_TRAVERSAL", "s,als,s|a", false )},
|
||||||
|
{ "TRAVERSAL_TREE", Function("GRAPH_TRAVERSAL_TREE", "s,als,s,s|a", false )},
|
||||||
|
{ "GRAPH_TRAVERSAL_TREE", Function("GENERAL_GRAPH_TRAVERSAL_TREE", "s,als,s,s|a", false )},
|
||||||
|
{ "EDGES", Function("GRAPH_EDGES", "h,s,s|l", false )},
|
||||||
|
{ "GRAPH_EDGES", Function("GENERAL_GRAPH_EDGES", "s,als|a", false )},
|
||||||
|
{ "GRAPH_VERTICES", Function("GENERAL_GRAPH_VERTICES", "s,als|a", false )},
|
||||||
|
{ "NEIGHBORS", Function("GRAPH_NEIGHBORS", "h,h,s,s|l", false )},
|
||||||
|
{ "GRAPH_NEIGHBORS", Function("GENERAL_GRAPH_NEIGHBORS", "s,als|a", false )},
|
||||||
|
{ "GRAPH_COMMON_NEIGHBORS", Function("GENERAL_GRAPH_COMMON_NEIGHBORS", "s,als,als|a,a", false )},
|
||||||
|
{ "GRAPH_COMMON_PROPERTIES", Function("GENERAL_GRAPH_COMMON_PROPERTIES", "s,als,als|a", false )},
|
||||||
|
{ "GRAPH_ECCENTRICITY", Function("GENERAL_GRAPH_ECCENTRICITY", "s|a", false )},
|
||||||
|
{ "GRAPH_BETWEENNESS", Function("GENERAL_GRAPH_BETWEENNESS", "s|a", false )},
|
||||||
|
{ "GRAPH_CLOSENESS", Function("GENERAL_GRAPH_CLOSENESS", "s|a", false )},
|
||||||
|
{ "GRAPH_ABSOLUTE_ECCENTRICITY", Function("GENERAL_GRAPH_ABSOLUTE_ECCENTRICITY", "s,als|a", false )},
|
||||||
|
{ "GRAPH_ABSOLUTE_CLOSENESS", Function("GENERAL_GRAPH_ABSOLUTE_CLOSENESS", "s,als|a", false )},
|
||||||
|
{ "GRAPH_DIAMETER", Function("GENERAL_GRAPH_DIAMETER", "s|a", false )},
|
||||||
|
{ "GRAPH_RADIUS", Function("GENERAL_GRAPH_RADIUS", "s|a", false )},
|
||||||
|
|
||||||
|
// date functions
|
||||||
|
{ "DATE_NOW", Function("DATE_NOW", "", false) },
|
||||||
|
{ "DATE_TIMESTAMP", Function("DATE_TIMESTAMP", "ns|ns,ns,ns,ns,ns,ns", true) },
|
||||||
|
{ "DATE_ISO8601", Function("DATE_ISO8601", "ns|ns,ns,ns,ns,ns,ns", true) },
|
||||||
|
{ "DATE_DAYOFWEEK", Function("DATE_DAYOFWEEK", "ns", true) },
|
||||||
|
{ "DATE_YEAR", Function("DATE_YEAR", "ns", true) },
|
||||||
|
{ "DATE_MONTH", Function("DATE_MONTH", "ns", true) },
|
||||||
|
{ "DATE_DAY", Function("DATE_DAY", "ns", true) },
|
||||||
|
{ "DATE_HOUR", Function("DATE_HOUR", "ns", true) },
|
||||||
|
{ "DATE_MINUTE", Function("DATE_MINUTE", "ns", true) },
|
||||||
|
{ "DATE_SECOND", Function("DATE_SECOND", "ns", true) },
|
||||||
|
{ "DATE_MILLISECOND", Function("DATE_MILLISECOND", "ns", true) },
|
||||||
|
|
||||||
|
// misc functions
|
||||||
|
{ "FAIL", Function("FAIL", "|s", false) },
|
||||||
|
{ "PASSTHRU", Function("PASSTHRU", ".", false) },
|
||||||
|
{ "SLEEP", Function("SLEEP", "n", false) },
|
||||||
|
{ "COLLECTIONS", Function("COLLECTIONS", "", false) },
|
||||||
|
{ "NOT_NULL", Function("NOT_NULL", ".|+", true) },
|
||||||
|
{ "FIRST_LIST", Function("FIRST_LIST", ".|+", true) },
|
||||||
|
{ "FIRST_DOCUMENT", Function("FIRST_DOCUMENT", ".|+", true) },
|
||||||
|
{ "PARSE_IDENTIFIER", Function("PARSE_IDENTIFIER", ".", true) },
|
||||||
|
{ "SKIPLIST", Function("SKIPLIST_QUERY", "h,a|n,n", false) },
|
||||||
|
{ "CURRENT_USER", Function("CURRENT_USER", "", false) },
|
||||||
|
{ "CURRENT_DATABASE", Function("CURRENT_DATABASE", "", false) }
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- constructors / destructors
|
// --SECTION-- constructors / destructors
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -97,7 +251,7 @@ V8Executor::~V8Executor () {
|
||||||
V8Expression* V8Executor::generateExpression (AstNode const* node) {
|
V8Expression* V8Executor::generateExpression (AstNode const* node) {
|
||||||
generateCodeExpression(node);
|
generateCodeExpression(node);
|
||||||
|
|
||||||
std::cout << "CREATED CODE: " << _buffer->c_str() << "\n";
|
std::cout << "Executor::generateExpression: " << _buffer->c_str() << "\n";
|
||||||
|
|
||||||
v8::Handle<v8::Script> compiled = v8::Script::Compile(v8::String::New(_buffer->c_str(), (int) _buffer->length()),
|
v8::Handle<v8::Script> compiled = v8::Script::Compile(v8::String::New(_buffer->c_str(), (int) _buffer->length()),
|
||||||
v8::String::New("--script--"));
|
v8::String::New("--script--"));
|
||||||
|
@ -111,6 +265,23 @@ V8Expression* V8Executor::generateExpression (AstNode const* node) {
|
||||||
|
|
||||||
if (tryCatch.HasCaught()) {
|
if (tryCatch.HasCaught()) {
|
||||||
if (tryCatch.CanContinue()) {
|
if (tryCatch.CanContinue()) {
|
||||||
|
if (tryCatch.Exception()->IsObject()) {
|
||||||
|
// cast the exception into an object
|
||||||
|
v8::Handle<v8::Array> objValue = v8::Handle<v8::Array>::Cast(tryCatch.Exception());
|
||||||
|
|
||||||
|
v8::Handle<v8::String> errorName = v8::String::New("errorName");
|
||||||
|
|
||||||
|
if (objValue->HasOwnProperty(errorName)) {
|
||||||
|
v8::Handle<v8::Value> errorNum = objValue->Get(errorName);
|
||||||
|
|
||||||
|
if (errorNum->IsNumber()) {
|
||||||
|
int errorCode = static_cast<int>(TRI_ObjectToInt64(errorNum));
|
||||||
|
// TODO: handle errors
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -122,6 +293,7 @@ V8Expression* V8Executor::generateExpression (AstNode const* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val.IsEmpty()) {
|
if (val.IsEmpty()) {
|
||||||
|
// out of memory
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,9 +308,26 @@ V8Expression* V8Executor::generateExpression (AstNode const* node) {
|
||||||
TRI_json_t* V8Executor::executeExpression (AstNode const* node) {
|
TRI_json_t* V8Executor::executeExpression (AstNode const* node) {
|
||||||
generateCodeExpression(node);
|
generateCodeExpression(node);
|
||||||
|
|
||||||
|
std::cout << "Executor::ExecuteExpression: " << _buffer->c_str() << "\n";
|
||||||
|
|
||||||
return execute();
|
return execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns a reference to a built-in function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Function const* V8Executor::getFunctionByName (std::string const& name) {
|
||||||
|
auto it = FunctionNames.find(name);
|
||||||
|
|
||||||
|
if (it == FunctionNames.end()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_NAME_UNKNOWN, name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the address of the function
|
||||||
|
return &((*it).second);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private methods
|
// --SECTION-- private methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -214,9 +403,9 @@ void V8Executor::generateCodeUnaryOperator (AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr);
|
TRI_ASSERT(node != nullptr);
|
||||||
TRI_ASSERT(node->numMembers() == 1);
|
TRI_ASSERT(node->numMembers() == 1);
|
||||||
|
|
||||||
auto it = FunctionNames.find(static_cast<int>(node->type));
|
auto it = InternalFunctionNames.find(static_cast<int>(node->type));
|
||||||
|
|
||||||
if (it == FunctionNames.end()) {
|
if (it == InternalFunctionNames.end()) {
|
||||||
// no function found for the type of node
|
// no function found for the type of node
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
@ -237,9 +426,9 @@ void V8Executor::generateCodeBinaryOperator (AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr);
|
TRI_ASSERT(node != nullptr);
|
||||||
TRI_ASSERT(node->numMembers() == 2);
|
TRI_ASSERT(node->numMembers() == 2);
|
||||||
|
|
||||||
auto it = FunctionNames.find(static_cast<int>(node->type));
|
auto it = InternalFunctionNames.find(static_cast<int>(node->type));
|
||||||
|
|
||||||
if (it == FunctionNames.end()) {
|
if (it == InternalFunctionNames.end()) {
|
||||||
// no function found for the type of node
|
// no function found for the type of node
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
@ -275,9 +464,9 @@ void V8Executor::generateCodeTernaryOperator (AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr);
|
TRI_ASSERT(node != nullptr);
|
||||||
TRI_ASSERT(node->numMembers() == 3);
|
TRI_ASSERT(node->numMembers() == 3);
|
||||||
|
|
||||||
auto it = FunctionNames.find(static_cast<int>(node->type));
|
auto it = InternalFunctionNames.find(static_cast<int>(node->type));
|
||||||
|
|
||||||
if (it == FunctionNames.end()) {
|
if (it == InternalFunctionNames.end()) {
|
||||||
// no function found for the type of node
|
// no function found for the type of node
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
@ -340,23 +529,23 @@ void V8Executor::generateCodeCollection (AstNode const* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief generate JavaScript code for a function call
|
/// @brief generate JavaScript code for a call to a built-in function
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void V8Executor::generateCodeFunctionCall (AstNode const* node) {
|
void V8Executor::generateCodeFunctionCall (AstNode const* node) {
|
||||||
TRI_ASSERT(node != nullptr);
|
TRI_ASSERT(node != nullptr);
|
||||||
TRI_ASSERT(node->numMembers() == 1);
|
TRI_ASSERT(node->numMembers() == 1);
|
||||||
|
|
||||||
char const* name = node->getStringValue();
|
auto func = static_cast<Function*>(node->getData());
|
||||||
|
|
||||||
_buffer->appendText("aql.");
|
|
||||||
_buffer->appendText(name);
|
|
||||||
_buffer->appendText("(");
|
|
||||||
|
|
||||||
auto args = node->getMember(0);
|
auto args = node->getMember(0);
|
||||||
TRI_ASSERT(args != nullptr);
|
TRI_ASSERT(args != nullptr);
|
||||||
TRI_ASSERT(args->type == NODE_TYPE_LIST);
|
TRI_ASSERT(args->type == NODE_TYPE_LIST);
|
||||||
|
|
||||||
|
_buffer->appendText("aql.");
|
||||||
|
_buffer->appendText(func->name);
|
||||||
|
_buffer->appendText("(");
|
||||||
|
|
||||||
size_t const n = args->numMembers();
|
size_t const n = args->numMembers();
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
@ -368,6 +557,36 @@ void V8Executor::generateCodeFunctionCall (AstNode const* node) {
|
||||||
_buffer->appendText(")");
|
_buffer->appendText(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief generate JavaScript code for a call to a user-defined function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void V8Executor::generateCodeUserFunctionCall (AstNode const* node) {
|
||||||
|
TRI_ASSERT(node != nullptr);
|
||||||
|
TRI_ASSERT(node->numMembers() == 1);
|
||||||
|
|
||||||
|
char const* name = node->getStringValue();
|
||||||
|
TRI_ASSERT(name != nullptr);
|
||||||
|
|
||||||
|
auto args = node->getMember(0);
|
||||||
|
TRI_ASSERT(args != nullptr);
|
||||||
|
TRI_ASSERT(args->type == NODE_TYPE_LIST);
|
||||||
|
|
||||||
|
_buffer->appendText("aql.FCALL_USER(\"");
|
||||||
|
_buffer->appendJsonEncoded(name);
|
||||||
|
_buffer->appendText("\", [");
|
||||||
|
|
||||||
|
size_t const n = args->numMembers();
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (i > 0) {
|
||||||
|
_buffer->appendText(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
generateCodeNode(args->getMember(i));
|
||||||
|
}
|
||||||
|
_buffer->appendText("])");
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief generate JavaScript code for an expansion (i.e. [*] operator)
|
/// @brief generate JavaScript code for an expansion (i.e. [*] operator)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -497,6 +716,10 @@ void V8Executor::generateCodeNode (AstNode const* node) {
|
||||||
generateCodeFunctionCall(node);
|
generateCodeFunctionCall(node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_TYPE_FCALL_USER:
|
||||||
|
generateCodeUserFunctionCall(node);
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_TYPE_EXPAND:
|
case NODE_TYPE_EXPAND:
|
||||||
generateCodeExpand(node);
|
generateCodeExpand(node);
|
||||||
break;
|
break;
|
||||||
|
@ -560,6 +783,7 @@ TRI_json_t* V8Executor::execute () {
|
||||||
// it will fail badly
|
// it will fail badly
|
||||||
|
|
||||||
TRI_ASSERT(_buffer != nullptr);
|
TRI_ASSERT(_buffer != nullptr);
|
||||||
|
|
||||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
|
||||||
v8::Handle<v8::Script> compiled = v8::Script::Compile(v8::String::New(_buffer->c_str(), (int) _buffer->length()),
|
v8::Handle<v8::Script> compiled = v8::Script::Compile(v8::String::New(_buffer->c_str(), (int) _buffer->length()),
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define ARANGODB_AQL_V8_EXECUTOR_H 1
|
#define ARANGODB_AQL_V8_EXECUTOR_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Aql/Function.h"
|
||||||
|
|
||||||
struct TRI_json_s;
|
struct TRI_json_s;
|
||||||
|
|
||||||
|
@ -86,6 +87,12 @@ namespace triagens {
|
||||||
|
|
||||||
struct TRI_json_s* executeExpression (AstNode const*);
|
struct TRI_json_s* executeExpression (AstNode const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns a reference to a built-in function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Function const* getFunctionByName (std::string const&);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private methods
|
// --SECTION-- private methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -147,11 +154,17 @@ namespace triagens {
|
||||||
void generateCodeCollection (AstNode const*);
|
void generateCodeCollection (AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief generate JavaScript code for a function call
|
/// @brief generate JavaScript code for a call to a built-in function
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void generateCodeFunctionCall (AstNode const*);
|
void generateCodeFunctionCall (AstNode const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief generate JavaScript code for a user-defined function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void generateCodeUserFunctionCall (AstNode const*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief generate JavaScript code for an expansion (i.e. [*] operator)
|
/// @brief generate JavaScript code for an expansion (i.e. [*] operator)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -213,11 +226,16 @@ namespace triagens {
|
||||||
triagens::basics::StringBuffer* _buffer;
|
triagens::basics::StringBuffer* _buffer;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief AQL function names
|
/// @brief AQL internal function names
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static std::unordered_map<int, std::string> const FunctionNames;
|
static std::unordered_map<int, std::string const> const InternalFunctionNames;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief AQL user-callable function names
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, Function const> const FunctionNames;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,33 @@ namespace triagens {
|
||||||
values->Set(v8::String::New(varname.c_str(), (int) varname.size()), argv[startPos + reg].toV8(trx, docColls[reg]));
|
values->Set(v8::String::New(varname.c_str(), (int) varname.size()), argv[startPos + reg].toV8(trx, docColls[reg]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set function arguments
|
||||||
v8::Handle<v8::Value> args[] = { values };
|
v8::Handle<v8::Value> args[] = { values };
|
||||||
|
|
||||||
|
// execute the function
|
||||||
|
v8::TryCatch tryCatch;
|
||||||
v8::Handle<v8::Value> result = func->Call(func, 1, args);
|
v8::Handle<v8::Value> result = func->Call(func, 1, args);
|
||||||
|
|
||||||
|
if (tryCatch.HasCaught()) {
|
||||||
|
if (tryCatch.CanContinue()) {
|
||||||
|
if (tryCatch.Exception()->IsObject()) {
|
||||||
|
// cast the exception into an object
|
||||||
|
v8::Handle<v8::Array> objValue = v8::Handle<v8::Array>::Cast(tryCatch.Exception());
|
||||||
|
v8::Handle<v8::String> errorNum = v8::String::New("errorNum");
|
||||||
|
|
||||||
|
if (objValue->HasOwnProperty(errorNum)) {
|
||||||
|
v8::Handle<v8::Value> errorNumValue = objValue->Get(errorNum);
|
||||||
|
|
||||||
|
if (errorNumValue->IsNumber()) {
|
||||||
|
int errorCode = static_cast<int>(TRI_ObjectToInt64(errorNumValue));
|
||||||
|
THROW_ARANGO_EXCEPTION(errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: handle case when we can NOT continue
|
||||||
|
}
|
||||||
|
|
||||||
if (result.IsEmpty()) {
|
if (result.IsEmpty()) {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,14 +34,28 @@ using namespace std;
|
||||||
using namespace triagens::arango;
|
using namespace triagens::arango;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief constructor
|
/// @brief constructor, without format string
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Exception::Exception (int code,
|
Exception::Exception (int code,
|
||||||
string const& details,
|
|
||||||
char const* file,
|
char const* file,
|
||||||
int line)
|
int line)
|
||||||
: _details(details),
|
: _errorMessage(TRI_errno_string(code)),
|
||||||
|
_file(file),
|
||||||
|
_line(line),
|
||||||
|
_code(code) {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor, for creating an exception with an already created
|
||||||
|
/// error message (normally based on error templates containing %s, %d etc.)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Exception::Exception (int code,
|
||||||
|
string const& errorMessage,
|
||||||
|
char const* file,
|
||||||
|
int line)
|
||||||
|
: _errorMessage(errorMessage),
|
||||||
_file(file),
|
_file(file),
|
||||||
_line(line),
|
_line(line),
|
||||||
_code(code) {
|
_code(code) {
|
||||||
|
@ -74,20 +88,7 @@ char const* Exception::what () const throw () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
string Exception::message () const throw () {
|
string Exception::message () const throw () {
|
||||||
string message(TRI_errno_string(_code));
|
return _errorMessage;
|
||||||
|
|
||||||
if (strstr(message.c_str(), "%s") != nullptr) {
|
|
||||||
// error message contains "%s" wildcard
|
|
||||||
try {
|
|
||||||
// replace %s with actual details
|
|
||||||
return basics::StringUtils::replace(message, "%s", _details);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
return "internal error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -98,6 +99,25 @@ int Exception::code () const throw () {
|
||||||
return _code;
|
return _code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief construct an error message from a template string
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string Exception::FillExceptionString (int code,
|
||||||
|
...) {
|
||||||
|
char const* format = TRI_errno_string(code);
|
||||||
|
TRI_ASSERT(format != nullptr);
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, code);
|
||||||
|
vsnprintf(buffer, sizeof(buffer) - 1, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0'; // Windows
|
||||||
|
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- END-OF-FILE
|
// --SECTION-- END-OF-FILE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -44,14 +44,14 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define THROW_ARANGO_EXCEPTION(code) \
|
#define THROW_ARANGO_EXCEPTION(code) \
|
||||||
throw triagens::arango::Exception(code, "", __FILE__, __LINE__)
|
throw triagens::arango::Exception(code, __FILE__, __LINE__)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief throws an exception for internal errors
|
/// @brief throws an exception for internal errors
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define THROW_ARANGO_EXCEPTION_STRING(code, details) \
|
#define THROW_ARANGO_EXCEPTION_PARAMS(code, ...) \
|
||||||
throw triagens::arango::Exception(code, details, __FILE__, __LINE__)
|
throw triagens::arango::Exception(code, triagens::arango::Exception::FillExceptionString(code, __VA_ARGS__), __FILE__, __LINE__)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public types
|
// --SECTION-- public types
|
||||||
|
@ -67,7 +67,11 @@ namespace triagens {
|
||||||
class Exception : public virtual std::exception {
|
class Exception : public virtual std::exception {
|
||||||
public:
|
public:
|
||||||
Exception (int code,
|
Exception (int code,
|
||||||
std::string const& details,
|
char const* file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
Exception (int code,
|
||||||
|
std::string const& errorMessage,
|
||||||
char const* file,
|
char const* file,
|
||||||
int line);
|
int line);
|
||||||
|
|
||||||
|
@ -80,8 +84,10 @@ namespace triagens {
|
||||||
|
|
||||||
int code () const throw();
|
int code () const throw();
|
||||||
|
|
||||||
|
static std::string FillExceptionString (int, ...);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string const _details;
|
std::string const _errorMessage;
|
||||||
char const* _file;
|
char const* _file;
|
||||||
int const _line;
|
int const _line;
|
||||||
int const _code;
|
int const _code;
|
||||||
|
|
|
@ -160,7 +160,7 @@
|
||||||
"ERROR_QUERY_TOO_MANY_COLLECTIONS" : { "code" : 1522, "message" : "too many collections" },
|
"ERROR_QUERY_TOO_MANY_COLLECTIONS" : { "code" : 1522, "message" : "too many collections" },
|
||||||
"ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED" : { "code" : 1530, "message" : "document attribute '%s' is assigned multiple times" },
|
"ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED" : { "code" : 1530, "message" : "document attribute '%s' is assigned multiple times" },
|
||||||
"ERROR_QUERY_FUNCTION_NAME_UNKNOWN" : { "code" : 1540, "message" : "usage of unknown function '%s()'" },
|
"ERROR_QUERY_FUNCTION_NAME_UNKNOWN" : { "code" : 1540, "message" : "usage of unknown function '%s()'" },
|
||||||
"ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH" : { "code" : 1541, "message" : "invalid number of arguments for function '%s()'" },
|
"ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH" : { "code" : 1541, "message" : "invalid number of arguments for function '%s()', expected number of arguments: minimum: %d, maximum: %d" },
|
||||||
"ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH" : { "code" : 1542, "message" : "invalid argument type used in call to function '%s()'" },
|
"ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH" : { "code" : 1542, "message" : "invalid argument type used in call to function '%s()'" },
|
||||||
"ERROR_QUERY_INVALID_REGEX" : { "code" : 1543, "message" : "invalid regex argument value used in call to function '%s()'" },
|
"ERROR_QUERY_INVALID_REGEX" : { "code" : 1543, "message" : "invalid regex argument value used in call to function '%s()'" },
|
||||||
"ERROR_QUERY_BIND_PARAMETERS_INVALID" : { "code" : 1550, "message" : "invalid structure of bind parameters" },
|
"ERROR_QUERY_BIND_PARAMETERS_INVALID" : { "code" : 1550, "message" : "invalid structure of bind parameters" },
|
||||||
|
|
|
@ -160,7 +160,7 @@
|
||||||
"ERROR_QUERY_TOO_MANY_COLLECTIONS" : { "code" : 1522, "message" : "too many collections" },
|
"ERROR_QUERY_TOO_MANY_COLLECTIONS" : { "code" : 1522, "message" : "too many collections" },
|
||||||
"ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED" : { "code" : 1530, "message" : "document attribute '%s' is assigned multiple times" },
|
"ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED" : { "code" : 1530, "message" : "document attribute '%s' is assigned multiple times" },
|
||||||
"ERROR_QUERY_FUNCTION_NAME_UNKNOWN" : { "code" : 1540, "message" : "usage of unknown function '%s()'" },
|
"ERROR_QUERY_FUNCTION_NAME_UNKNOWN" : { "code" : 1540, "message" : "usage of unknown function '%s()'" },
|
||||||
"ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH" : { "code" : 1541, "message" : "invalid number of arguments for function '%s()'" },
|
"ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH" : { "code" : 1541, "message" : "invalid number of arguments for function '%s()', expected number of arguments: minimum: %d, maximum: %d" },
|
||||||
"ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH" : { "code" : 1542, "message" : "invalid argument type used in call to function '%s()'" },
|
"ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH" : { "code" : 1542, "message" : "invalid argument type used in call to function '%s()'" },
|
||||||
"ERROR_QUERY_INVALID_REGEX" : { "code" : 1543, "message" : "invalid regex argument value used in call to function '%s()'" },
|
"ERROR_QUERY_INVALID_REGEX" : { "code" : 1543, "message" : "invalid regex argument value used in call to function '%s()'" },
|
||||||
"ERROR_QUERY_BIND_PARAMETERS_INVALID" : { "code" : 1550, "message" : "invalid structure of bind parameters" },
|
"ERROR_QUERY_BIND_PARAMETERS_INVALID" : { "code" : 1550, "message" : "invalid structure of bind parameters" },
|
||||||
|
|
|
@ -196,7 +196,7 @@ ERROR_QUERY_COLLECTION_LOCK_FAILED,1521,"unable to read-lock collection %s","Wil
|
||||||
ERROR_QUERY_TOO_MANY_COLLECTIONS,1522,"too many collections","Will be raised when the number of collections in a query is beyond the allowed value."
|
ERROR_QUERY_TOO_MANY_COLLECTIONS,1522,"too many collections","Will be raised when the number of collections in a query is beyond the allowed value."
|
||||||
ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED,1530,"document attribute '%s' is assigned multiple times","Will be raised when a document attribute is re-assigned."
|
ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED,1530,"document attribute '%s' is assigned multiple times","Will be raised when a document attribute is re-assigned."
|
||||||
ERROR_QUERY_FUNCTION_NAME_UNKNOWN,1540,"usage of unknown function '%s()'","Will be raised when an undefined function is called."
|
ERROR_QUERY_FUNCTION_NAME_UNKNOWN,1540,"usage of unknown function '%s()'","Will be raised when an undefined function is called."
|
||||||
ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH,1541,"invalid number of arguments for function '%s()'","Will be raised when the number of arguments used in a function call does not match the expected number of arguments for the function."
|
ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH,1541,"invalid number of arguments for function '%s()', expected number of arguments: minimum: %d, maximum: %d","Will be raised when the number of arguments used in a function call does not match the expected number of arguments for the function."
|
||||||
ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,1542,"invalid argument type used in call to function '%s()'","Will be raised when the type of an argument used in a function call does not match the expected argument type."
|
ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,1542,"invalid argument type used in call to function '%s()'","Will be raised when the type of an argument used in a function call does not match the expected argument type."
|
||||||
ERROR_QUERY_INVALID_REGEX,1543,"invalid regex argument value used in call to function '%s()'","Will be raised when an invalid regex argument value is used in a call to a function that expects a regex."
|
ERROR_QUERY_INVALID_REGEX,1543,"invalid regex argument value used in call to function '%s()'","Will be raised when an invalid regex argument value is used in a call to a function that expects a regex."
|
||||||
ERROR_QUERY_BIND_PARAMETERS_INVALID,1550,"invalid structure of bind parameters","Will be raised when the structure of bind parameters passed has an unexpected format."
|
ERROR_QUERY_BIND_PARAMETERS_INVALID,1550,"invalid structure of bind parameters","Will be raised when the structure of bind parameters passed has an unexpected format."
|
||||||
|
|
|
@ -156,7 +156,7 @@ void TRI_InitialiseErrorMessages (void) {
|
||||||
REG_ERROR(ERROR_QUERY_TOO_MANY_COLLECTIONS, "too many collections");
|
REG_ERROR(ERROR_QUERY_TOO_MANY_COLLECTIONS, "too many collections");
|
||||||
REG_ERROR(ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED, "document attribute '%s' is assigned multiple times");
|
REG_ERROR(ERROR_QUERY_DOCUMENT_ATTRIBUTE_REDECLARED, "document attribute '%s' is assigned multiple times");
|
||||||
REG_ERROR(ERROR_QUERY_FUNCTION_NAME_UNKNOWN, "usage of unknown function '%s()'");
|
REG_ERROR(ERROR_QUERY_FUNCTION_NAME_UNKNOWN, "usage of unknown function '%s()'");
|
||||||
REG_ERROR(ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "invalid number of arguments for function '%s()'");
|
REG_ERROR(ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "invalid number of arguments for function '%s()', expected number of arguments: minimum: %d, maximum: %d");
|
||||||
REG_ERROR(ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "invalid argument type used in call to function '%s()'");
|
REG_ERROR(ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "invalid argument type used in call to function '%s()'");
|
||||||
REG_ERROR(ERROR_QUERY_INVALID_REGEX, "invalid regex argument value used in call to function '%s()'");
|
REG_ERROR(ERROR_QUERY_INVALID_REGEX, "invalid regex argument value used in call to function '%s()'");
|
||||||
REG_ERROR(ERROR_QUERY_BIND_PARAMETERS_INVALID, "invalid structure of bind parameters");
|
REG_ERROR(ERROR_QUERY_BIND_PARAMETERS_INVALID, "invalid structure of bind parameters");
|
||||||
|
|
|
@ -8,7 +8,7 @@ extern "C" {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @page ArangoErrors Error codes and meanings
|
/// @page ArangoErrors Error codes and meanings
|
||||||
/// @startDocuBlock errorCodes
|
///
|
||||||
/// The following errors might be raised when running ArangoDB:
|
/// The following errors might be raised when running ArangoDB:
|
||||||
///
|
///
|
||||||
/// - 0: @LIT{no error}
|
/// - 0: @LIT{no error}
|
||||||
|
@ -371,7 +371,7 @@ extern "C" {
|
||||||
/// Will be raised when a document attribute is re-assigned.
|
/// Will be raised when a document attribute is re-assigned.
|
||||||
/// - 1540: @LIT{usage of unknown function '\%s()'}
|
/// - 1540: @LIT{usage of unknown function '\%s()'}
|
||||||
/// Will be raised when an undefined function is called.
|
/// Will be raised when an undefined function is called.
|
||||||
/// - 1541: @LIT{invalid number of arguments for function '\%s()'}
|
/// - 1541: @LIT{invalid number of arguments for function '\%s()', expected number of arguments: minimum: \%d, maximum: \%d}
|
||||||
/// Will be raised when the number of arguments used in a function call does
|
/// Will be raised when the number of arguments used in a function call does
|
||||||
/// not match the expected number of arguments for the function.
|
/// not match the expected number of arguments for the function.
|
||||||
/// - 1542: @LIT{invalid argument type used in call to function '\%s()'}
|
/// - 1542: @LIT{invalid argument type used in call to function '\%s()'}
|
||||||
|
@ -586,7 +586,6 @@ extern "C" {
|
||||||
/// Will be returned if the element was not found in the structure.
|
/// Will be returned if the element was not found in the structure.
|
||||||
/// - 20000: @LIT{newest version of app already installed}
|
/// - 20000: @LIT{newest version of app already installed}
|
||||||
/// newest version of app already installed
|
/// newest version of app already installed
|
||||||
/// @endDocuBlock
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2122,7 +2121,8 @@ void TRI_InitialiseErrorMessages (void);
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief 1541: ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH
|
/// @brief 1541: ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH
|
||||||
///
|
///
|
||||||
/// invalid number of arguments for function '%s()'
|
/// invalid number of arguments for function '%s()', expected number of
|
||||||
|
/// arguments: minimum: %d, maximum: %d
|
||||||
///
|
///
|
||||||
/// Will be raised when the number of arguments used in a function call does
|
/// Will be raised when the number of arguments used in a function call does
|
||||||
/// not match the expected number of arguments for the function.
|
/// not match the expected number of arguments for the function.
|
||||||
|
|
Loading…
Reference in New Issue