1
0
Fork 0

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

This commit is contained in:
James 2014-10-14 09:22:20 +01:00
commit 362dc083cc
14 changed files with 898 additions and 424 deletions

View File

@ -129,7 +129,13 @@ v2.3.0 (XXXX-XX-XX)
storing JavaScript date objects in the database in a sensible manner. storing JavaScript date objects in the database in a sensible manner.
v2.2.x (????-??-??) v2.2.6 (XXXX-XX-XX)
-------------------
* fixed issue #972: Compilation Issue
v2.2.5 (2014-10-09)
------------------- -------------------
* fixed issue #961: allow non-JSON values in undocument request bodies * fixed issue #961: allow non-JSON values in undocument request bodies
@ -140,7 +146,7 @@ v2.2.x (????-??-??)
problems after collection rename operations problems after collection rename operations
v2.2.4 (2014-XX-XX) v2.2.4 (2014-10-01)
------------------- -------------------
* fixed accessing `_from` and `_to` attributes in `collection.byExample` and * fixed accessing `_from` and `_to` attributes in `collection.byExample` and

91
arangod/Aql/Arithmetic.h Normal file
View File

@ -0,0 +1,91 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief arithmetic helpers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-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 triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_AQL_ARITHMETIC_H
#define ARANGODB_AQL_ARITHMETIC_H 1
#include "Basics/Common.h"
namespace triagens {
namespace aql {
template<typename T>
bool IsUnsafeAddition (T l, T r) {
return ((r > 0 && l > std::numeric_limits<T>::max() - r) ||
(r < 0 && l < std::numeric_limits<T>::min() - r));
}
template<typename T>
bool IsUnsafeSubtraction (T l, T r) {
return ((r > 0 && l < std::numeric_limits<T>::min() + r) || (r < 0 && l > std::numeric_limits<T>::max() + r));
}
template<typename T>
bool IsUnsafeMultiplication (T l, T r) {
if (l > 0) {
if (r > 0) {
if (l > (std::numeric_limits<T>::max() / r)) {
return true;
}
}
else {
if (r < (std::numeric_limits<T>::min() / l)) {
return true;
}
}
}
else {
if (r > 0) {
if (l < (std::numeric_limits<T>::min() / r)) {
return true;
}
}
else {
if ( (l != 0) && (r < (std::numeric_limits<T>::max() / l))) {
return true;
}
}
}
return false;
}
template<typename T>
bool IsUnsafeDivision (T l, T r) {
return (l == std::numeric_limits<T>::min() && r == -1);
}
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -28,6 +28,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "Aql/Ast.h" #include "Aql/Ast.h"
#include "Aql/Arithmetic.h"
#include "Aql/Collection.h" #include "Aql/Collection.h"
#include "Aql/Executor.h" #include "Aql/Executor.h"
#include "Basics/tri-strings.h" #include "Basics/tri-strings.h"
@ -41,10 +42,28 @@ using namespace triagens::aql;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief initialise a singleton NOP node instance /// @brief initialise a singleton no-op node instance
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AstNode const Ast::NopNode = { NODE_TYPE_NOP }; AstNode const Ast::NopNode{ NODE_TYPE_NOP };
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise a singleton null node instance
////////////////////////////////////////////////////////////////////////////////
AstNode const Ast::NullNode{ NODE_TYPE_VALUE, VALUE_TYPE_NULL };
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise a singleton false node instance
////////////////////////////////////////////////////////////////////////////////
AstNode const Ast::FalseNode{ false };
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise a singleton true node instance
////////////////////////////////////////////////////////////////////////////////
AstNode const Ast::TrueNode{ true };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief inverse comparison operators /// @brief inverse comparison operators
@ -587,10 +606,9 @@ AstNode* Ast::createNodeIterator (char const* variableName,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createNodeValueNull () { AstNode* Ast::createNodeValueNull () {
AstNode* node = createNode(NODE_TYPE_VALUE); // return a pointer to the singleton null node
node->setValueType(VALUE_TYPE_NULL); // note: this node is never registered nor freed
return const_cast<AstNode*>(&NullNode);
return node;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -598,11 +616,12 @@ AstNode* Ast::createNodeValueNull () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createNodeValueBool (bool value) { AstNode* Ast::createNodeValueBool (bool value) {
AstNode* node = createNode(NODE_TYPE_VALUE); // return a pointer to the singleton bool nodes
node->setValueType(VALUE_TYPE_BOOL); // note: these nodes are never registered nor freed
node->setBoolValue(value); if (value) {
return const_cast<AstNode*>(&TrueNode);
return node; }
return const_cast<AstNode*>(&FalseNode);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1034,6 +1053,32 @@ AstNode* Ast::clone (AstNode const* node) {
// --SECTION-- private methods // --SECTION-- private methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create a number node for an arithmetic result, integer
////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createArithmeticResultNode (int64_t value) {
return createNodeValueInt(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a number node for an arithmetic result, double
////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createArithmeticResultNode (double value) {
if (value != value ||
value == HUGE_VAL ||
value == - HUGE_VAL) {
// IEEE754 NaN values have an interesting property that we can exploit...
// if the architecture does not use IEEE754 values then this shouldn't do
// any harm either
// TODO: log an error: _query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
return createNodeValueNull();
}
return createNodeValueDouble(value);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief executes an expression with constant parameters /// @brief executes an expression with constant parameters
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1080,27 +1125,26 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
return node; return node;
} }
if (! operand->isNumericValue()) { // operand is a constant, now convert it into a number
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE); auto converted = operand->castToNumber(this);
return node;
}
TRI_ASSERT(operand->value.type == VALUE_TYPE_INT || if (converted->isNullValue()) {
operand->value.type == VALUE_TYPE_DOUBLE); return createNodeValueNull();
}
if (node->type == NODE_TYPE_OPERATOR_UNARY_PLUS) { if (node->type == NODE_TYPE_OPERATOR_UNARY_PLUS) {
// + number => number // + number => number
return operand; return converted;
} }
else { else {
// - number // - number
if (operand->value.type == VALUE_TYPE_INT) { if (converted->value.type == VALUE_TYPE_INT) {
// int64 // int64
return createNodeValueInt(- operand->getIntValue()); return createNodeValueInt(- converted->getIntValue());
} }
else { else {
// double // double
double const value = - operand->getDoubleValue(); double const value = - converted->getDoubleValue();
if (value != value || if (value != value ||
value == HUGE_VAL || value == HUGE_VAL ||
@ -1108,13 +1152,14 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
// IEEE754 NaN values have an interesting property that we can exploit... // IEEE754 NaN values have an interesting property that we can exploit...
// if the architecture does not use IEEE754 values then this shouldn't do // if the architecture does not use IEEE754 values then this shouldn't do
// any harm either // any harm either
_query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE); return createNodeValueNull();
return node;
} }
return createNodeValueDouble(value); return createNodeValueDouble(value);
} }
} }
TRI_ASSERT(false);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1160,13 +1205,10 @@ AstNode* Ast::optimizeUnaryOperatorLogical (AstNode* node) {
return optimizeNotExpression(node); return optimizeNotExpression(node);
} }
if (! operand->isBoolValue()) { auto converted = operand->castToBool(this);
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
// replace unary negation operation with result of negation // replace unary negation operation with result of negation
return createNodeValueBool(! operand->getBoolValue()); return createNodeValueBool(! converted->getBoolValue());
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1186,55 +1228,31 @@ AstNode* Ast::optimizeBinaryOperatorLogical (AstNode* node) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
} }
bool const lhsIsConst = lhs->isConstant(); if (lhs->isConstant()) {
bool const rhsIsConst = rhs->isConstant(); if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
// left operand is a constant value
if (lhsIsConst && ! lhs->isBoolValue()) { if (lhs->isFalse()) {
// left operand is a constant value, but no boolean // return it if it is falsey
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
if (rhsIsConst && ! rhs->isBoolValue()) {
// right operand is a constant value, but no boolean
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
if (! lhsIsConst) {
if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
if (rhsIsConst && ! rhs->getBoolValue()) {
// (lhs || false) => lhs
return lhs; return lhs;
} }
}
// default: don't optimize // left-operand was trueish, now return right operand
return node;
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
// logical and
if (lhs->getBoolValue()) {
// (true && rhs) => rhs
return rhs; return rhs;
} }
else if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
// left operand is a constant value
if (lhs->isTrue()) {
// return it if it is trueish
return lhs;
}
// (false && rhs) => false // left-operand was falsey, now return right operand
return lhs; return rhs;
}
else {
// logical or
if (lhs->getBoolValue()) {
// (true || rhs) => true
return lhs;
} }
// (false || rhs) => rhs
return rhs;
} }
// default case
return node;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1288,9 +1306,8 @@ AstNode* Ast::optimizeBinaryOperatorRelational (AstNode* node) {
if (rhs->type != NODE_TYPE_LIST && if (rhs->type != NODE_TYPE_LIST &&
(node->type == NODE_TYPE_OPERATOR_BINARY_IN || (node->type == NODE_TYPE_OPERATOR_BINARY_IN ||
node->type == NODE_TYPE_OPERATOR_BINARY_NIN)) { node->type == NODE_TYPE_OPERATOR_BINARY_NIN)) {
// right operand of IN or NOT IN must be a list // right operand of IN or NOT IN must be a list, otherwise we return false
_query->registerError(TRI_ERROR_QUERY_LIST_EXPECTED); return createNodeValueBool(false);
return node;
} }
if (! lhsIsConst) { if (! lhsIsConst) {
@ -1315,71 +1332,137 @@ AstNode* Ast::optimizeBinaryOperatorArithmetic (AstNode* node) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
} }
bool const lhsIsConst = lhs->isConstant(); if (lhs->isConstant() && rhs->isConstant()) {
bool const rhsIsConst = rhs->isConstant(); // now calculate the expression result
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) {
// TODO: add string concatenation
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
if (lhsIsConst && ! lhs->isNumericValue()) { bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
// lhs is not a number
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
return node;
}
if (rhsIsConst && ! rhs->isNumericValue()) {
// rhs is not a number
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
return node;
}
if (! lhsIsConst || ! rhsIsConst) { if (! useDoublePrecision) {
return node; auto l = left->getIntValue();
} auto r = right->getIntValue();
// check if the result would overflow
// now calculate the expression result useDoublePrecision = IsUnsafeAddition<int64_t>(l, r);
double value; if (! useDoublePrecision) {
double const l = lhs->getDoubleValue(); // can calculate using integers
double const r = rhs->getDoubleValue(); return createArithmeticResultNode(l + r);
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) { }
value = l + r;
} // must use double precision
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MINUS) { return createArithmeticResultNode(left->getDoubleValue() + right->getDoubleValue());
value = l - r;
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_TIMES) {
value = l * r;
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_DIV) {
if (r == 0.0) {
_query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return node;
} }
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MINUS) {
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
value = l / r; bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MOD) { if (! useDoublePrecision) {
if (r == 0.0) { auto l = left->getIntValue();
_query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO); auto r = right->getIntValue();
return node; // check if the result would overflow
useDoublePrecision = IsUnsafeSubtraction<int64_t>(l, r);
if (! useDoublePrecision) {
// can calculate using integers
return createArithmeticResultNode(l - r);
}
}
// must use double precision
return createArithmeticResultNode(left->getDoubleValue() - right->getDoubleValue());
} }
else if (node->type == NODE_TYPE_OPERATOR_BINARY_TIMES) {
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
value = fmod(l, r); bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
}
else { if (! useDoublePrecision) {
auto l = left->getIntValue();
auto r = right->getIntValue();
// check if the result would overflow
useDoublePrecision = IsUnsafeMultiplication<int64_t>(l, r);
if (! useDoublePrecision) {
// can calculate using integers
return createArithmeticResultNode(l * r);
}
}
// must use double precision
return createArithmeticResultNode(left->getDoubleValue() * right->getDoubleValue());
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_DIV) {
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
if (! useDoublePrecision) {
auto l = left->getIntValue();
auto r = right->getIntValue();
if (r == 0) {
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return createNodeValueNull();
}
// check if the result would overflow
useDoublePrecision = (IsUnsafeDivision<int64_t>(l, r) || r < -1 || r > 1);
if (! useDoublePrecision) {
// can calculate using integers
return createArithmeticResultNode(l / r);
}
}
if (right->getDoubleValue() == 0.0) {
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return createNodeValueNull();
}
return createArithmeticResultNode(left->getDoubleValue() / right->getDoubleValue());
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MOD) {
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
if (! useDoublePrecision) {
auto l = left->getIntValue();
auto r = right->getIntValue();
if (r == 0) {
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return createNodeValueNull();
}
// check if the result would overflow
useDoublePrecision = IsUnsafeDivision<int64_t>(l, r);
if (! useDoublePrecision) {
// can calculate using integers
return createArithmeticResultNode(l % r);
}
}
if (right->getDoubleValue() == 0.0) {
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return createNodeValueNull();
}
return createArithmeticResultNode(fmod(left->getDoubleValue(), right->getDoubleValue()));
}
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid operator"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid operator");
} }
if (value != value ||
value == HUGE_VAL ||
value == - HUGE_VAL) {
// IEEE754 NaN values have an interesting property that we can exploit...
// if the architecture does not use IEEE754 values then this shouldn't do
// any harm either
_query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
return node;
}
return createNodeValueDouble(value); return node;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1407,12 +1490,7 @@ AstNode* Ast::optimizeTernaryOperator (AstNode* node) {
return node; return node;
} }
if (! condition->isBoolValue()) { if (condition->isTrue()) {
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
if (condition->getBoolValue()) {
// condition is always true, replace ternary operation with true part // condition is always true, replace ternary operation with true part
return truePart; return truePart;
} }
@ -1662,6 +1740,7 @@ AstNode* Ast::createNode (AstNodeType type) {
auto node = new AstNode(type); auto node = new AstNode(type);
try { try {
// register the node so it gets freed automatically later
_query->addNode(node); _query->addNode(node);
} }
catch (...) { catch (...) {

View File

@ -495,6 +495,18 @@ namespace triagens {
private: private:
////////////////////////////////////////////////////////////////////////////////
/// @brief create a number node for an arithmetic result, integer
////////////////////////////////////////////////////////////////////////////////
AstNode* createArithmeticResultNode (int64_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief create a number node for an arithmetic result, double
////////////////////////////////////////////////////////////////////////////////
AstNode* createArithmeticResultNode (double);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief executes an expression with constant parameters /// @brief executes an expression with constant parameters
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -652,11 +664,29 @@ namespace triagens {
AstNode const* _writeCollection; AstNode const* _writeCollection;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief a singleton NOP node instance /// @brief a singleton no-op node instance
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static AstNode const NopNode; static AstNode const NopNode;
////////////////////////////////////////////////////////////////////////////////
/// @brief a singleton null node instance
////////////////////////////////////////////////////////////////////////////////
static AstNode const NullNode;
////////////////////////////////////////////////////////////////////////////////
/// @brief a singleton false node instance
////////////////////////////////////////////////////////////////////////////////
static AstNode const FalseNode;
////////////////////////////////////////////////////////////////////////////////
/// @brief a singleton true node instance
////////////////////////////////////////////////////////////////////////////////
static AstNode const TrueNode;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief inverse comparison operators /// @brief inverse comparison operators
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -140,6 +140,30 @@ AstNode::AstNode (AstNodeType type)
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief create a node, with defining a value type
////////////////////////////////////////////////////////////////////////////////
AstNode::AstNode (AstNodeType type,
AstNodeValueType valueType)
: AstNode(type) {
value.type = valueType;
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a boolean node, with defining a value
////////////////////////////////////////////////////////////////////////////////
AstNode::AstNode (bool v)
: AstNode(NODE_TYPE_VALUE) {
value.type = VALUE_TYPE_BOOL;
value.value._bool = v;
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create the node from JSON /// @brief create the node from JSON
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -405,6 +429,67 @@ TRI_json_t* AstNode::toJsonValue (TRI_memory_zone_t* zone) const {
return nullptr; return nullptr;
} }
std::string AstNode::toInfoString (TRI_memory_zone_t* zone) const {
std::string ret;
ret += std::string(" of Type '");
ret += getTypeString();
ret += std::string("' ");
if (type == NODE_TYPE_COLLECTION ||
type == NODE_TYPE_PARAMETER ||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
type == NODE_TYPE_ARRAY_ELEMENT ||
type == NODE_TYPE_FCALL_USER) {
// dump "name" of node
ret += std::string(" by Name ");
ret += getStringValue();
}
if (type == NODE_TYPE_FCALL) {
auto func = static_cast<Function*>(getData());
ret += std::string(" by Name '");
ret += func->externalName;
ret += std::string("' with Parameters");
}
if (type == NODE_TYPE_VALUE) {
// dump value of "value" node
ret += std::string(" with Value(s) ");
/// TODO: auto v = toJsonValue(zone);
}
if (type == NODE_TYPE_VARIABLE ||
type == NODE_TYPE_REFERENCE) {
auto variable = static_cast<Variable*>(getData());
ret += std::string(" by Name(");
ret += variable->name;
ret += std::string(") ");
}
// dump sub-nodes
size_t const n = members._length;
if (n > 0) {
ret += std::string("(");
try {
for (size_t i = 0; i < n; ++i) {
auto member = getMember(i);
if (member != nullptr && member->type != NODE_TYPE_NOP) {
ret += member->toInfoString(zone);
}
}
}
catch (...) {
ret += std::string("Invalid Subnode!");
}
ret += std::string(")");
}
return ret;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the node /// @brief return a JSON representation of the node
/// the caller is responsible for freeing the JSON later /// the caller is responsible for freeing the JSON later
@ -497,67 +582,103 @@ TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone,
return node; return node;
} }
std::string AstNode::toInfoString (TRI_memory_zone_t* zone) const { ////////////////////////////////////////////////////////////////////////////////
std::string ret; /// @brief convert the node's value to a boolean value
/// this may create a new node or return the node itself if it is already a
/// boolean value node
////////////////////////////////////////////////////////////////////////////////
ret += std::string(" of Type '"); AstNode* AstNode::castToBool (Ast* ast) {
ret += getTypeString(); TRI_ASSERT(type == NODE_TYPE_VALUE ||
ret += std::string("' "); type == NODE_TYPE_LIST ||
type == NODE_TYPE_ARRAY);
if (type == NODE_TYPE_COLLECTION ||
type == NODE_TYPE_PARAMETER ||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
type == NODE_TYPE_ARRAY_ELEMENT ||
type == NODE_TYPE_FCALL_USER) {
// dump "name" of node
ret += std::string(" by Name ");
ret += getStringValue();
}
if (type == NODE_TYPE_FCALL) {
auto func = static_cast<Function*>(getData());
ret += std::string(" by Name '");
ret += func->externalName;
ret += std::string("' with Parameters");
}
if (type == NODE_TYPE_VALUE) { if (type == NODE_TYPE_VALUE) {
// dump value of "value" node switch (value.type) {
ret += std::string(" with Value(s) "); case VALUE_TYPE_NULL:
/// TODO: auto v = toJsonValue(zone); // null => false
} return ast->createNodeValueBool(false);
case VALUE_TYPE_BOOL:
if (type == NODE_TYPE_VARIABLE || // already a boolean
type == NODE_TYPE_REFERENCE) { return this;
auto variable = static_cast<Variable*>(getData()); case VALUE_TYPE_INT:
ret += std::string(" by Name("); return ast->createNodeValueBool(value.value._int != 0);
ret += variable->name; case VALUE_TYPE_DOUBLE:
ret += std::string(") "); return ast->createNodeValueBool(value.value._double != 0.0);
} case VALUE_TYPE_STRING:
return ast->createNodeValueBool(*(value.value._string) != '\0');
// dump sub-nodes default: {
size_t const n = members._length;
if (n > 0) {
ret += std::string("(");
try {
for (size_t i = 0; i < n; ++i) {
auto member = getMember(i);
if (member != nullptr && member->type != NODE_TYPE_NOP) {
ret += member->toInfoString(zone);
}
} }
} }
catch (...) { // fall-through intentional
ret += std::string("Invalid Subnode!"); }
} else if (type == NODE_TYPE_LIST) {
// fall-through intentional
ret += std::string(")"); }
else if (type == NODE_TYPE_ARRAY) {
// fall-through intentional
} }
return ret; return ast->createNodeValueBool(false);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief convert the node's value to a number value
/// this may create a new node or return the node itself if it is already a
/// numeric value node
////////////////////////////////////////////////////////////////////////////////
AstNode* AstNode::castToNumber (Ast* ast) {
TRI_ASSERT(type == NODE_TYPE_VALUE ||
type == NODE_TYPE_LIST ||
type == NODE_TYPE_ARRAY);
if (type == NODE_TYPE_VALUE) {
switch (value.type) {
case VALUE_TYPE_NULL:
// null => 0
return ast->createNodeValueInt(0);
case VALUE_TYPE_BOOL:
// false => 0, true => 1
return ast->createNodeValueInt(value.value._bool ? 1 : 0);
case VALUE_TYPE_INT:
case VALUE_TYPE_DOUBLE:
// already numeric!
return this;
case VALUE_TYPE_STRING:
try {
// try converting string to number
double v = std::stod(value.value._string);
return ast->createNodeValueDouble(v);
}
catch (...) {
// conversion failed
}
// fall-through intentional
default: {
}
}
// fall-through intentional
}
else if (type == NODE_TYPE_LIST) {
size_t const n = numMembers();
if (n == 0) {
// [ ] => 0
return ast->createNodeValueInt(0);
}
else if (n == 1) {
auto member = getMember(0);
// convert only member to number
return member->castToNumber(ast);
}
// fall-through intentional
}
else if (type == NODE_TYPE_ARRAY) {
// fall-through intentional
}
return ast->createNodeValueNull();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief adds a JSON representation of the node to the JSON list specified /// @brief adds a JSON representation of the node to the JSON list specified
@ -579,34 +700,84 @@ void AstNode::toJson (TRI_json_t* json,
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief convert the node's value to a boolean value /// @brief get the integer value of a node, provided the node is a value node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool AstNode::toBoolean () const { int64_t AstNode::getIntValue () const {
if (type == NODE_TYPE_VALUE) { if (type == NODE_TYPE_VALUE) {
switch (value.type) { switch (value.type) {
case VALUE_TYPE_BOOL: { case VALUE_TYPE_NULL:
return value.value._bool; return 0;
} case VALUE_TYPE_BOOL:
case VALUE_TYPE_INT: { return (value.value._bool ? 1 : 0);
return (value.value._int != 0); case VALUE_TYPE_INT:
} return value.value._int;
case VALUE_TYPE_DOUBLE: { case VALUE_TYPE_DOUBLE:
return value.value._double != 0.0; return static_cast<int64_t>(value.value._double);
} case VALUE_TYPE_STRING:
case VALUE_TYPE_STRING: { return 0;
return (*value.value._string != '\0');
}
case VALUE_TYPE_NULL:
case VALUE_TYPE_FAIL: {
return false;
}
} }
} }
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the double value of a node, provided the node is a value node
////////////////////////////////////////////////////////////////////////////////
double AstNode::getDoubleValue () const {
if (type == NODE_TYPE_VALUE) {
switch (value.type) {
case VALUE_TYPE_NULL:
return 0.0;
case VALUE_TYPE_BOOL:
return (value.value._bool ? 1.0 : 0.0);
case VALUE_TYPE_INT:
return static_cast<double>(value.value._int);
case VALUE_TYPE_DOUBLE:
return value.value._double;
case VALUE_TYPE_STRING:
return 0.0;
}
}
return 0.0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the node value is trueish
////////////////////////////////////////////////////////////////////////////////
bool AstNode::isTrue () const {
if (type == NODE_TYPE_VALUE) {
switch (value.type) {
case VALUE_TYPE_NULL:
return false;
case VALUE_TYPE_BOOL:
return value.value._bool;
case VALUE_TYPE_INT:
return (value.value._int != 0);
case VALUE_TYPE_DOUBLE:
return value.value._double != 0.0;
case VALUE_TYPE_STRING:
return (*value.value._string != '\0');
}
}
else if (type == NODE_TYPE_LIST ||
type == NODE_TYPE_ARRAY) {
return true;
}
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the node value is falsey
////////////////////////////////////////////////////////////////////////////////
bool AstNode::isFalse () const {
return ! isTrue();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a node is simple enough to be used in a simple /// @brief whether or not a node is simple enough to be used in a simple
/// expression /// expression

View File

@ -51,12 +51,11 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
enum AstNodeValueType { enum AstNodeValueType {
VALUE_TYPE_FAIL = 0, VALUE_TYPE_NULL = 0,
VALUE_TYPE_NULL = 1, VALUE_TYPE_BOOL = 1,
VALUE_TYPE_BOOL = 2, VALUE_TYPE_INT = 2,
VALUE_TYPE_INT = 3, VALUE_TYPE_DOUBLE = 3,
VALUE_TYPE_DOUBLE = 4, VALUE_TYPE_STRING = 4
VALUE_TYPE_STRING = 5
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -154,7 +153,19 @@ namespace triagens {
/// @brief create the node /// @brief create the node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AstNode (AstNodeType); explicit AstNode (AstNodeType);
////////////////////////////////////////////////////////////////////////////////
/// @brief create a node, with defining a value type
////////////////////////////////////////////////////////////////////////////////
explicit AstNode (AstNodeType, AstNodeValueType);
////////////////////////////////////////////////////////////////////////////////
/// @brief create a boolean, with defining a value type
////////////////////////////////////////////////////////////////////////////////
explicit AstNode (bool);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create the node from JSON /// @brief create the node from JSON
@ -212,6 +223,8 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
TRI_json_t* toJsonValue (TRI_memory_zone_t*) const; TRI_json_t* toJsonValue (TRI_memory_zone_t*) const;
std::string toInfoString (TRI_memory_zone_t* zone) const;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief return a JSON representation of the node /// @brief return a JSON representation of the node
@ -221,8 +234,6 @@ namespace triagens {
TRI_json_t* toJson (TRI_memory_zone_t*, TRI_json_t* toJson (TRI_memory_zone_t*,
bool) const; bool) const;
std::string toInfoString (TRI_memory_zone_t* zone) const;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief adds a JSON representation of the node to the JSON list specified /// @brief adds a JSON representation of the node to the JSON list specified
/// in the first argument /// in the first argument
@ -234,9 +245,55 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief convert the node's value to a boolean value /// @brief convert the node's value to a boolean value
/// this may create a new node or return the node itself if it is already a
/// boolean value node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool toBoolean () const; AstNode* castToBool (Ast*);
////////////////////////////////////////////////////////////////////////////////
/// @brief convert the node's value to a number value
/// this may create a new node or return the node itself if it is already a
/// numeric value node
////////////////////////////////////////////////////////////////////////////////
AstNode* castToNumber (Ast*);
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the node value is trueish
////////////////////////////////////////////////////////////////////////////////
bool isTrue () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the node value is falsey
////////////////////////////////////////////////////////////////////////////////
bool isFalse () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a value node is NULL
////////////////////////////////////////////////////////////////////////////////
inline bool isNullValue () const {
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_NULL);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a value node is an integer
////////////////////////////////////////////////////////////////////////////////
inline bool isIntValue () const {
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_INT);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a value node is a dobule
////////////////////////////////////////////////////////////////////////////////
inline bool isDoubleValue () const {
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_DOUBLE);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a value node is of numeric type /// @brief whether or not a value node is of numeric type
@ -401,28 +458,10 @@ namespace triagens {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief return the int value of a node, without asserting the node type /// @brief return the int value of a node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
inline int64_t getIntValue (bool) const { int64_t getIntValue () const;
return value.value._int;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the int value of a node, with asserting the node type
////////////////////////////////////////////////////////////////////////////////
inline int64_t getIntValue () const {
TRI_ASSERT(type == NODE_TYPE_VALUE);
TRI_ASSERT(value.type == VALUE_TYPE_INT ||
value.type == VALUE_TYPE_DOUBLE);
if (value.type == VALUE_TYPE_DOUBLE) {
return static_cast<int64_t>(value.value._double);
}
return value.value._int;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief set the int value of a node /// @brief set the int value of a node
@ -436,17 +475,7 @@ namespace triagens {
/// @brief return the double value of a node /// @brief return the double value of a node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
inline double getDoubleValue () const { double getDoubleValue () const;
TRI_ASSERT(type == NODE_TYPE_VALUE);
TRI_ASSERT(value.type == VALUE_TYPE_INT ||
value.type == VALUE_TYPE_DOUBLE);
if (value.type == VALUE_TYPE_INT) {
return static_cast<double>(value.value._int);
}
return value.value._double;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief set the string value of a node /// @brief set the string value of a node

View File

@ -237,14 +237,14 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
TRI_ASSERT(value->isConstant()); TRI_ASSERT(value->isConstant());
if (strcmp(name, "waitForSync") == 0) { if (strcmp(name, "waitForSync") == 0) {
options.waitForSync = value->toBoolean(); options.waitForSync = value->isTrue();
} }
else if (strcmp(name, "ignoreErrors") == 0) { else if (strcmp(name, "ignoreErrors") == 0) {
options.ignoreErrors = value->toBoolean(); options.ignoreErrors = value->isTrue();
} }
else if (strcmp(name, "keepNull") == 0) { else if (strcmp(name, "keepNull") == 0) {
// nullMeansRemove is the opposite of keepNull // nullMeansRemove is the opposite of keepNull
options.nullMeansRemove = (! value->toBoolean()); options.nullMeansRemove = value->isFalse();
} }
} }
} }

View File

@ -217,7 +217,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
// we can now evaluate it safely // we can now evaluate it safely
TRI_ASSERT(! s->expression()->canThrow()); TRI_ASSERT(! s->expression()->canThrow());
if (root->toBoolean()) { if (root->isTrue()) {
// filter is always true // filter is always true
// remove filter node and merge with following node // remove filter node and merge with following node
toUnlink.insert(n); toUnlink.insert(n);

View File

@ -445,9 +445,9 @@ function executeAndWait (cmd, args) {
if (typeof(res.errorMessage) !== 'undefined') { if (typeof(res.errorMessage) !== 'undefined') {
errorMessage += res.errorMessage; errorMessage += res.errorMessage;
} }
print("Finished: " + res.status + " Exitcode: " + res.exit + " Time Elapsed: " + deltaTime + errorMessage); print("Finished: " + res.status + " Exitcode: " + res.signal + " Time Elapsed: " + deltaTime + errorMessage);
return { return {
status: false, status: res.status === 'RUNNING',
message: "irregular termination: " + res.status + " Exit-Code: " + res.exit + errorMessage, message: "irregular termination: " + res.status + " Exit-Code: " + res.exit + errorMessage,
duration: deltaTime duration: deltaTime
}; };

View File

@ -28,7 +28,7 @@
var errors = require("internal").errors; var errors = require("internal").errors;
var jsunity = require("jsunity"); var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper"); var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2; var getQueryResults = helper.getQueryResultsAQL2;
var assertQueryError = helper.assertQueryError2; var assertQueryError = helper.assertQueryError2;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -107,13 +107,18 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test unary plus /// @brief test unary plus
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testUnaryPlusInvalid : function () { testUnaryPlusNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +null"); assertEqual([ 0 ], getQueryResults("RETURN +null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +true"); assertEqual([ 1 ], getQueryResults("RETURN +true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +false"); assertEqual([ 0 ], getQueryResults("RETURN +false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +\"value\""); assertEqual([ null ], getQueryResults("RETURN +\"value\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +[ ]"); assertEqual([ 1 ], getQueryResults("RETURN +\"1\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +{ }"); assertEqual([ -3 ], getQueryResults("RETURN +\"-3\""));
assertEqual([ 0 ], getQueryResults("RETURN +[ ]"));
assertEqual([ 0 ], getQueryResults("RETURN +[ 0 ]"));
assertEqual([ -34 ], getQueryResults("RETURN +[ -34 ]"));
assertEqual([ null ], getQueryResults("RETURN +[ 1, 2 ]"));
assertEqual([ null ], getQueryResults("RETURN +{ }"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -170,13 +175,18 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test unary minus /// @brief test unary minus
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testUnaryMinusInvalid : function () { testUnaryMinusNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -null"); assertEqual([ 0 ], getQueryResults("RETURN -null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -true"); assertEqual([ -1 ], getQueryResults("RETURN -true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -false"); assertEqual([ 0 ], getQueryResults("RETURN -false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -\"value\""); assertEqual([ null ], getQueryResults("RETURN -\"value\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -[ ]"); assertEqual([ -1 ], getQueryResults("RETURN -\"1\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -{ }"); assertEqual([ 3 ], getQueryResults("RETURN -\"-3\""));
assertEqual([ 0 ], getQueryResults("RETURN -[ ]"));
assertEqual([ 0 ], getQueryResults("RETURN -[ 0 ]"));
assertEqual([ 34 ], getQueryResults("RETURN -[ -34 ]"));
assertEqual([ null ], getQueryResults("RETURN -[ 1, 2 ]"));
assertEqual([ null ], getQueryResults("RETURN -{ }"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -254,19 +264,29 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test binary plus /// @brief test binary plus
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryPlusInvalid : function () { testBinaryPlusNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + null"); assertEqual([ 1 ], getQueryResults("RETURN 1 + null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + false"); assertEqual([ 1 ], getQueryResults("RETURN 1 + false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + \"0\""); assertEqual([ 2 ], getQueryResults("RETURN 1 + true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ ]"); assertEqual([ 1 ], getQueryResults("RETURN 1 + \"0\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ 0 ]"); assertEqual([ 43 ], getQueryResults("RETURN 1 + \"42\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + { }"); assertEqual([ -16 ], getQueryResults("RETURN 1 + \"-17\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null + 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false + 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 + [ 0 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" + 1"); assertEqual([ 5 ], getQueryResults("RETURN 1 + [ 4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] + 1"); assertEqual([ -3 ], getQueryResults("RETURN 1 + [ -4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] + 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 + { }"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } + 1"); assertEqual([ 1 ], getQueryResults("RETURN null + 1"));
assertEqual([ 1 ], getQueryResults("RETURN false + 1"));
assertEqual([ 2 ], getQueryResults("RETURN true + 1"));
assertEqual([ 1 ], getQueryResults("RETURN \"0\" + 1"));
assertEqual([ 24 ], getQueryResults("RETURN \"23\" + 1"));
assertEqual([ -8 ], getQueryResults("RETURN \"-9\" + 1"));
assertEqual([ 1 ], getQueryResults("RETURN [ ] + 1"));
assertEqual([ 1 ], getQueryResults("RETURN [ 0 ] + 1"));
assertEqual([ 5 ], getQueryResults("RETURN [ 4 ] + 1"));
assertEqual([ -3 ], getQueryResults("RETURN [ -4 ] + 1"));
assertEqual([ 1 ], getQueryResults("RETURN { } + 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -303,19 +323,30 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test binary minus /// @brief test binary minus
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryMinusInvalid : function () { testBinaryMinusNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - null"); assertEqual([ 1 ], getQueryResults("RETURN 1 - null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - false"); assertEqual([ 1 ], getQueryResults("RETURN 1 - false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - \"0\""); assertEqual([ 0 ], getQueryResults("RETURN 1 - true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ ]"); assertEqual([ 1 ], getQueryResults("RETURN 1 - \"0\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ 0 ]"); assertEqual([ -41 ], getQueryResults("RETURN 1 - \"42\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - { }"); assertEqual([ 18 ], getQueryResults("RETURN 1 - \"-17\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null - 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 - [ ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false - 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 - [ 0 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" - 1"); assertEqual([ -3 ], getQueryResults("RETURN 1 - [ 4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] - 1"); assertEqual([ 5 ], getQueryResults("RETURN 1 - [ -4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] - 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 - { }"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } - 1"); assertEqual([ -1 ], getQueryResults("RETURN null - 1"));
assertEqual([ -1 ], getQueryResults("RETURN false - 1"));
assertEqual([ 0 ], getQueryResults("RETURN true - 1"));
assertEqual([ -1 ], getQueryResults("RETURN \"0\" - 1"));
assertEqual([ -1 ], getQueryResults("RETURN \"0\" - \"1\""));
assertEqual([ 22 ], getQueryResults("RETURN \"23\" - 1"));
assertEqual([ -10 ], getQueryResults("RETURN \"-9\" - 1"));
assertEqual([ -1 ], getQueryResults("RETURN [ ] - 1"));
assertEqual([ -1 ], getQueryResults("RETURN [ 0 ] - 1"));
assertEqual([ 3 ], getQueryResults("RETURN [ 4 ] - 1"));
assertEqual([ -5 ], getQueryResults("RETURN [ -4 ] - 1"));
assertEqual([ -1 ], getQueryResults("RETURN { } - 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -392,19 +423,31 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test binary multiplication /// @brief test binary multiplication
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryMultiplicationInvalid : function () { testBinaryMultiplicationNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * null"); assertEqual([ 0 ], getQueryResults("RETURN 1 * null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * false"); assertEqual([ 0 ], getQueryResults("RETURN 1 * false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * \"0\""); assertEqual([ 1 ], getQueryResults("RETURN 1 * true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ ]"); assertEqual([ 37 ], getQueryResults("RETURN 37 * true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ 0 ]"); assertEqual([ 0 ], getQueryResults("RETURN 1 * \"0\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * { }"); assertEqual([ 42 ], getQueryResults("RETURN 1 * \"42\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null * 1"); assertEqual([ -17 ], getQueryResults("RETURN 1 * \"-17\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false * 1"); assertEqual([ 0 ], getQueryResults("RETURN 1 * [ ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" * 1"); assertEqual([ 0 ], getQueryResults("RETURN 1 * [ 0 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] * 1"); assertEqual([ 4 ], getQueryResults("RETURN 1 * [ 4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] * 1"); assertEqual([ -4 ], getQueryResults("RETURN 1 * [ -4 ]"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } * 1"); assertEqual([ 0 ], getQueryResults("RETURN 1 * { }"));
assertEqual([ 0 ], getQueryResults("RETURN null * 1"));
assertEqual([ 0 ], getQueryResults("RETURN false * 1"));
assertEqual([ 1 ], getQueryResults("RETURN true * 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" * 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" * \"1\""));
assertEqual([ 23 ], getQueryResults("RETURN \"23\" * 1"));
assertEqual([ -9 ], getQueryResults("RETURN \"-9\" * 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ ] * 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] * 1"));
assertEqual([ 4 ], getQueryResults("RETURN [ 4 ] * 1"));
assertEqual([ -4 ], getQueryResults("RETURN [ -4 ] * 1"));
assertEqual([ 0 ], getQueryResults("RETURN { } * 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -491,22 +534,35 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test binary division /// @brief test binary division
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryDivisionInvalid : function () { testBinaryDivisionNonNumeric : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / null"); assertEqual([ null ], getQueryResults("RETURN 1 / (1 - 1)"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / false"); assertEqual([ null ], getQueryResults("RETURN 1 / 0"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / \"0\""); assertEqual([ null ], getQueryResults("RETURN 1 / 0.0"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ ]"); assertEqual([ null ], getQueryResults("RETURN 1 / (1 / 0)"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ 0 ]"); assertEqual([ null ], getQueryResults("RETURN 1 / null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / { }"); assertEqual([ null ], getQueryResults("RETURN 1 / false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null / 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 / true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false / 1"); assertEqual([ 37 ], getQueryResults("RETURN 37 / true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" / 1"); assertEqual([ null ], getQueryResults("RETURN 1 / \"0\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] / 1"); assertEqual([ 0.25 ], getQueryResults("RETURN 1 / \"4\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] / 1"); assertEqual([ -2 ], getQueryResults("RETURN 34 / \"-17\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } / 1"); assertEqual([ null ], getQueryResults("RETURN 1 / [ ]"));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0"); assertEqual([ null ], getQueryResults("RETURN 1 / [ 0 ]"));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0.0"); assertEqual([ 0.25 ], getQueryResults("RETURN 1 / [ 4 ]"));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / (1 - 1)"); assertEqual([ -0.25 ], getQueryResults("RETURN 1 / [ -4 ]"));
assertEqual([ null ], getQueryResults("RETURN 1 / { }"));
assertEqual([ 0 ], getQueryResults("RETURN null / 1"));
assertEqual([ 0 ], getQueryResults("RETURN false / 1"));
assertEqual([ 1 ], getQueryResults("RETURN true / 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" / 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" / \"1\""));
assertEqual([ 23 ], getQueryResults("RETURN \"23\" / 1"));
assertEqual([ -9 ], getQueryResults("RETURN \"-9\" / 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ ] / 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] / 1"));
assertEqual([ 4 ], getQueryResults("RETURN [ 4 ] / 1"));
assertEqual([ -4 ], getQueryResults("RETURN [ -4 ] / 1"));
assertEqual([ 0 ], getQueryResults("RETURN { } / 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -514,21 +570,45 @@ function ahuacatlArithmeticTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryModulusInvalid : function () { testBinaryModulusInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % null"); assertEqual([ null ], getQueryResults("RETURN 1 % (1 - 1)"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % false"); assertEqual([ null ], getQueryResults("RETURN 1 % 0"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % \"0\""); assertEqual([ null ], getQueryResults("RETURN 1 % 0.0"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ ]"); assertEqual([ null ], getQueryResults("RETURN 1 % (1 / 0)"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ 0 ]"); assertEqual([ null ], getQueryResults("RETURN 1 % null"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % { }"); assertEqual([ null ], getQueryResults("RETURN 1 % false"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null % 1"); assertEqual([ 0 ], getQueryResults("RETURN 1 % true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false % 1"); assertEqual([ 0 ], getQueryResults("RETURN 37 % true"));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" % 1"); assertEqual([ null ], getQueryResults("RETURN 1 % \"0\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] % 1"); assertEqual([ 1 ], getQueryResults("RETURN 1 % \"4\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] % 1"); assertEqual([ 3 ], getQueryResults("RETURN 7 % \"4\""));
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } % 1"); assertEqual([ 3 ], getQueryResults("RETURN 7 % \"-4\""));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0"); assertEqual([ 0 ], getQueryResults("RETURN 34 % \"-17\""));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0.0"); assertEqual([ 1 ], getQueryResults("RETURN 35 % \"17\""));
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % (1 - 1)"); assertEqual([ 1 ], getQueryResults("RETURN 35 % \"-17\""));
assertEqual([ null ], getQueryResults("RETURN 1 % [ ]"));
assertEqual([ null ], getQueryResults("RETURN 1 % [ 0 ]"));
assertEqual([ 1 ], getQueryResults("RETURN 13 % [ 4 ]"));
assertEqual([ 1 ], getQueryResults("RETURN 1 % [ -4 ]"));
assertEqual([ 1 ], getQueryResults("RETURN 13 % [ -4 ]"));
assertEqual([ null ], getQueryResults("RETURN 1 % { }"));
assertEqual([ 0 ], getQueryResults("RETURN null % 1"));
assertEqual([ 0 ], getQueryResults("RETURN false % 1"));
assertEqual([ 0 ], getQueryResults("RETURN true % 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" % 1"));
assertEqual([ 0 ], getQueryResults("RETURN \"0\" % \"1\""));
assertEqual([ 0 ], getQueryResults("RETURN \"23\" % 1"));
assertEqual([ 1 ], getQueryResults("RETURN \"23\" % 2"));
assertEqual([ 2 ], getQueryResults("RETURN \"23\" % 3"));
assertEqual([ 2 ], getQueryResults("RETURN \"23\" % 7"));
assertEqual([ 11 ], getQueryResults("RETURN \"23\" % 12"));
assertEqual([ 11 ], getQueryResults("RETURN \"23\" % \"12\""));
assertEqual([ 0 ], getQueryResults("RETURN \"-9\" % 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ ] % 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] % 1"));
assertEqual([ 0 ], getQueryResults("RETURN [ 4 ] % 1"));
assertEqual([ 1 ], getQueryResults("RETURN [ 4 ] % 3"));
assertEqual([ 0 ], getQueryResults("RETURN [ -4 ] % 1"));
assertEqual([ 0 ], getQueryResults("RETURN { } % 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -411,16 +411,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testInvalidIn : function () { testInvalidIn : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN null RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN null RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN false RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN false RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN 1.2 RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN 1.2 RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN '' RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN '' RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN {} RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN {} RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: null }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: null }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: false }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: false }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: 1.2 }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: 1.2 }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: "" }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: "" }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: { } }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: { } }));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -428,16 +428,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testInvalidNotIn : function () { testInvalidNotIn : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN null RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN null RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN false RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN false RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN 1.2 RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN 1.2 RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN '' RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN '' RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN {} RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN {} RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: null }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: null }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: false }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: false }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: 1.2 }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: 1.2 }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: "" }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: "" }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: { } }); assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: { } }));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -445,16 +445,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testInvalidInCollection : function () { testInvalidInCollection : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN null RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN null RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN false RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN false RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN 1.2 RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN 1.2 RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN '' RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN '' RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN {} RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN {} RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: null }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: null }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: false }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: false }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: 1.2 }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: 1.2 }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: "" }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: "" }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: { } }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: { } }));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -462,16 +462,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testInvalidNotInCollection : function () { testInvalidNotInCollection : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN null RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN null RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN false RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN false RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN 1.2 RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN 1.2 RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN '' RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN '' RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN {} RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN {} RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: null }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: null }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: false }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: false }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: 1.2 }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: 1.2 }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: "" }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: "" }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: { } }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: { } }));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -479,16 +479,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testInvalidInCollectionIndex : function () { testInvalidInCollectionIndex : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN null RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN null RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN false RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN false RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN 1.2 RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN 1.2 RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN '' RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN '' RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN {} RETURN i"); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN {} RETURN i"));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: null }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: null }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: false }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: false }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: 1.2 }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: 1.2 }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: "" }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: "" }));
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: { } }); assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: { } }));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,7 @@
var errors = require("internal").errors; var errors = require("internal").errors;
var jsunity = require("jsunity"); var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper"); var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2; var getQueryResults = helper.getQueryResultsAQL2;
var assertQueryError = helper.assertQueryError2; var assertQueryError = helper.assertQueryError2;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -167,14 +167,19 @@ function ahuacatlTernaryTestSuite () {
/// @brief test ternary with non-boolean condition /// @brief test ternary with non-boolean condition
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testTernaryInvalid : function () { testTernaryNonBoolean : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN 1 ? 2 : 3"); assertEqual([ 2 ], getQueryResults("RETURN 1 ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN null ? 2 : 3"); assertEqual([ 3 ], getQueryResults("RETURN 0 ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4) ? 2 : 3"); assertEqual([ 3 ], getQueryResults("RETURN null ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4 - 3) ? 2 : 3"); assertEqual([ 3 ], getQueryResults("RETURN false ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN \"true\" ? 2 : 3"); assertEqual([ 2 ], getQueryResults("RETURN true ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN [ ] ? 2 : 3"); assertEqual([ 2 ], getQueryResults("RETURN (4) ? 2 : 3"));
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN { } ? 2 : 3"); assertEqual([ 2 ], getQueryResults("RETURN (4 - 3) ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN \"true\" ? 2 : 3"));
assertEqual([ 3 ], getQueryResults("RETURN \"\" ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN [ ] ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN [ 0 ] ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN { } ? 2 : 3"));
} }
}; };

View File

@ -1,3 +1,6 @@
/*jshint strict: false */
/*global require, assertTrue, assertEqual, assertMatch, fail */
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test the task manager /// @brief test the task manager
/// ///
@ -421,7 +424,7 @@ function TaskSuite () {
assertEqual(10, task.offset); assertEqual(10, task.offset);
assertEqual("_system", task.database); assertEqual("_system", task.database);
t = getTasks(); var t = getTasks();
assertEqual(1, t.length); assertEqual(1, t.length);
internal.wait(2); internal.wait(2);
@ -456,7 +459,7 @@ function TaskSuite () {
assertEqual(2, task.offset); assertEqual(2, task.offset);
assertEqual("_system", task.database); assertEqual("_system", task.database);
t = getTasks(); var t = getTasks();
assertEqual(1, t.length); assertEqual(1, t.length);
internal.wait(5); internal.wait(5);
@ -492,7 +495,7 @@ function TaskSuite () {
internal.wait(1); internal.wait(1);
t = getTasks(); var t = getTasks();
assertEqual(0, t.length); assertEqual(0, t.length);
internal.wait(5); internal.wait(5);
@ -526,7 +529,7 @@ function TaskSuite () {
assertEqual(5, task.offset); assertEqual(5, task.offset);
assertEqual("_system", task.database); assertEqual("_system", task.database);
t = getTasks(); var t = getTasks();
assertEqual(1, t.length); assertEqual(1, t.length);
internal.wait(15); internal.wait(15);
@ -572,7 +575,7 @@ function TaskSuite () {
assertEqual(0, db[cn].count()); assertEqual(0, db[cn].count());
assertEqual(0, db[cn].byExample({ value: 23 }).toArray().length); assertEqual(0, db[cn].byExample({ value: 23 }).toArray().length);
t = getTasks(); var t = getTasks();
assertEqual(0, t.length); assertEqual(0, t.length);
}, },

View File

@ -48,7 +48,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#ifdef WIN32 #ifdef _WIN32
#include <Psapi.h> #include <Psapi.h>
#include <TlHelp32.h> #include <TlHelp32.h>
#endif #endif
@ -220,15 +220,6 @@ static bool CreatePipes (int* pipe_server_to_child,
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief handler for SIGCHLD
////////////////////////////////////////////////////////////////////////////////
static void handleSigchld (int sig) {
// intentionally do nothing here
// we'll use waitpid() for reaping children later
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief starts external process /// @brief starts external process
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1280,17 +1271,6 @@ void TRI_InitialiseProcess (int argc, char* argv[]) {
TRI_InitVectorPointer(&ExternalProcesses, TRI_CORE_MEM_ZONE); TRI_InitVectorPointer(&ExternalProcesses, TRI_CORE_MEM_ZONE);
TRI_InitMutex(&ExternalProcessesLock); TRI_InitMutex(&ExternalProcessesLock);
#ifndef WIN32
// initialise a signal handler for SIGCHLD
struct sigaction sa;
sa.sa_handler = &handleSigchld;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa, 0) == -1) {
// installation of signal handler failed
}
#endif
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////