1
0
Fork 0

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

This commit is contained in:
Max Neunhoeffer 2014-08-29 11:09:44 +02:00
commit aefea865f5
4 changed files with 95 additions and 87 deletions

View File

@ -51,8 +51,8 @@ Function::Function (std::string const& externalName,
arguments(arguments),
isDeterministic(isDeterministic),
canThrow(canThrow),
containsCollectionParameter(false),
implementation(implementation) {
implementation(implementation),
conversions() {
initArguments();
}
@ -68,56 +68,16 @@ Function::~Function () {
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a positional argument needs to be converted from a
/// collection parameter to a collection name parameter
////////////////////////////////////////////////////////////////////////////////
bool Function::mustConvertArgument (size_t position) const {
bool foundArg = false;
size_t i = 0;
char const* p = arguments.c_str();
while (true) {
char const c = *p++;
switch (c) {
case '\0':
return false;
case '|':
case ',':
if (foundArg) {
if (++i > position) {
return false;
}
}
foundArg = false;
break;
case 'h':
if (i == position) {
// found an argument to convert
return true;
}
foundArg = true;
break;
default:
foundArg = true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse the argument list and set the minimum and maximum number of
/// arguments
////////////////////////////////////////////////////////////////////////////////
void Function::initArguments () {
minRequiredArguments = maxRequiredArguments = 0;
minRequiredArguments = 0;
maxRequiredArguments = 0;
size_t position = 0;
// setup some parsing state
bool inOptional = false;
@ -140,6 +100,7 @@ void Function::initArguments () {
case '|':
// beginning of optional arguments
++position;
TRI_ASSERT(! inOptional);
if (foundArg) {
++minRequiredArguments;
@ -151,6 +112,7 @@ void Function::initArguments () {
case ',':
// next argument
++position;
TRI_ASSERT(foundArg);
if (! inOptional) {
@ -166,12 +128,35 @@ void Function::initArguments () {
maxRequiredArguments = MaxArguments;
return;
default:
if (c == 'h') {
// note that we found a collection parameter
containsCollectionParameter = true;
case 'h':
// we found a collection parameter
// set the conversion info for the position
if (conversions.size() <= position) {
// we don't yet have another parameter at this position
conversions.push_back(CONVERSION_REQUIRED);
}
else if (conversions[position] == CONVERSION_NONE) {
// we already had a parameter at this position
conversions[position] = CONVERSION_OPTIONAL;
}
foundArg = true;
break;
default:
// we found any other parameter
// set the conversion info for the position
if (conversions.size() <= position) {
// we don't yet have another parameter at this position
conversions.push_back(CONVERSION_NONE);
}
else if (conversions[position] == CONVERSION_REQUIRED) {
// we already had a parameter at this position
conversions[position] = CONVERSION_OPTIONAL;
}
foundArg = true;
break;
}
}
}

View File

@ -38,6 +38,12 @@ namespace triagens {
struct Function {
enum Conversion {
CONVERSION_NONE,
CONVERSION_OPTIONAL,
CONVERSION_REQUIRED
};
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
@ -87,7 +93,12 @@ namespace triagens {
/// collection parameter to a collection name parameter
////////////////////////////////////////////////////////////////////////////////
bool mustConvertArgument (size_t) const;
inline Conversion getArgumentConversion (size_t position) const {
if (position >= conversions.size()) {
return CONVERSION_NONE;
}
return conversions[position];
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse the argument list and set the minimum and maximum number of
@ -104,63 +115,62 @@ namespace triagens {
/// @brief function name (name used in JavaScript implementation)
////////////////////////////////////////////////////////////////////////////////
std::string const internalName;
std::string const internalName;
////////////////////////////////////////////////////////////////////////////////
/// @brief function name (name visible to the end user)
////////////////////////////////////////////////////////////////////////////////
std::string const externalName;
std::string const externalName;
////////////////////////////////////////////////////////////////////////////////
/// @brief function arguments
////////////////////////////////////////////////////////////////////////////////
std::string const 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;
bool const isDeterministic;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the function may throw a runtime exception
////////////////////////////////////////////////////////////////////////////////
bool const canThrow;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the function contains a collection parameter that
/// will cause some special conversion during function calls
////////////////////////////////////////////////////////////////////////////////
bool containsCollectionParameter;
bool const canThrow;
////////////////////////////////////////////////////////////////////////////////
/// @brief minimum number of required arguments
////////////////////////////////////////////////////////////////////////////////
size_t minRequiredArguments;
size_t minRequiredArguments;
////////////////////////////////////////////////////////////////////////////////
/// @brief maximum number of required arguments
////////////////////////////////////////////////////////////////////////////////
size_t maxRequiredArguments;
size_t maxRequiredArguments;
////////////////////////////////////////////////////////////////////////////////
/// @brief C++ implementation of the function (maybe nullptr)
////////////////////////////////////////////////////////////////////////////////
FunctionImplementation implementation;
FunctionImplementation implementation;
////////////////////////////////////////////////////////////////////////////////
/// @brief function argument conversion information
////////////////////////////////////////////////////////////////////////////////
std::vector<Conversion> conversions;
////////////////////////////////////////////////////////////////////////////////
/// @brief maximum number of function arguments that can be used
////////////////////////////////////////////////////////////////////////////////
static size_t const MaxArguments = 1024;
static size_t const MaxArguments = 1024;
};

View File

@ -623,28 +623,28 @@ void V8Executor::generateCodeFunctionCall (AstNode const* node) {
auto member = args->getMember(i);
if (member != nullptr) {
if (func->containsCollectionParameter &&
member->type == NODE_TYPE_COLLECTION &&
func->mustConvertArgument(i)) {
// the parameter at this position is a collection name that is converted to a string
// do a parameter conversion from a collection parameter to a collection name parameter
char const* name = member->getStringValue();
generateCodeString(name);
}
/*
else {
// the parameter at the position is not a collection name... fail
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, func->internalName.c_str());
}
}
*/
else {
// generate regular code for the node
generateCodeNode(args->getMember(i));
}
if (member == nullptr) {
continue;
}
auto conversion = func->getArgumentConversion(i);
if (member->type == NODE_TYPE_COLLECTION &&
(conversion == Function::CONVERSION_REQUIRED || conversion == Function::CONVERSION_OPTIONAL)) {
// the parameter at this position is a collection name that is converted to a string
// do a parameter conversion from a collection parameter to a collection name parameter
char const* name = member->getStringValue();
generateCodeString(name);
}
else if (conversion == Function::CONVERSION_REQUIRED) {
// the parameter at the position is not a collection name... fail
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, func->internalName.c_str());
}
else {
generateCodeNode(args->getMember(i));
}
}
_buffer->appendText(")");
}

View File

@ -3420,6 +3420,14 @@ function GEO_NEAR (collection, latitude, longitude, limit, distanceAttribute) {
// use default value
limit = 100;
}
else if (TYPEWEIGHT(limit) !== TYPEWEIGHT_NUMBER) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "NEAR");
}
var weight = TYPEWEIGHT(distanceAttribute);
if (weight !== TYPEWEIGHT_NULL && weight !== TYPEWEIGHT_STRING) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "NEAR");
}
if (isCoordinator) {
var query = COLLECTION(collection).near(latitude, longitude);
@ -3462,6 +3470,11 @@ function GEO_WITHIN (collection, latitude, longitude, radius, distanceAttribute)
query._distance = distanceAttribute;
return query.toArray();
}
var weight = TYPEWEIGHT(distanceAttribute);
if (weight !== TYPEWEIGHT_NULL && weight !== TYPEWEIGHT_STRING) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "NEAR");
}
var idx = INDEX(COLLECTION(collection), [ "geo1", "geo2" ]);