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.
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
@ -140,7 +146,7 @@ v2.2.x (????-??-??)
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

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/Arithmetic.h"
#include "Aql/Collection.h"
#include "Aql/Executor.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
@ -587,10 +606,9 @@ AstNode* Ast::createNodeIterator (char const* variableName,
////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createNodeValueNull () {
AstNode* node = createNode(NODE_TYPE_VALUE);
node->setValueType(VALUE_TYPE_NULL);
return node;
// return a pointer to the singleton null node
// note: this node is never registered nor freed
return const_cast<AstNode*>(&NullNode);
}
////////////////////////////////////////////////////////////////////////////////
@ -598,11 +616,12 @@ AstNode* Ast::createNodeValueNull () {
////////////////////////////////////////////////////////////////////////////////
AstNode* Ast::createNodeValueBool (bool value) {
AstNode* node = createNode(NODE_TYPE_VALUE);
node->setValueType(VALUE_TYPE_BOOL);
node->setBoolValue(value);
return node;
// return a pointer to the singleton bool nodes
// note: these nodes are never registered nor freed
if (value) {
return const_cast<AstNode*>(&TrueNode);
}
return const_cast<AstNode*>(&FalseNode);
}
////////////////////////////////////////////////////////////////////////////////
@ -1034,6 +1053,32 @@ AstNode* Ast::clone (AstNode const* node) {
// --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
////////////////////////////////////////////////////////////////////////////////
@ -1080,27 +1125,26 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
return node;
}
if (! operand->isNumericValue()) {
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
return node;
}
// operand is a constant, now convert it into a number
auto converted = operand->castToNumber(this);
TRI_ASSERT(operand->value.type == VALUE_TYPE_INT ||
operand->value.type == VALUE_TYPE_DOUBLE);
if (converted->isNullValue()) {
return createNodeValueNull();
}
if (node->type == NODE_TYPE_OPERATOR_UNARY_PLUS) {
// + number => number
return operand;
return converted;
}
else {
// - number
if (operand->value.type == VALUE_TYPE_INT) {
if (converted->value.type == VALUE_TYPE_INT) {
// int64
return createNodeValueInt(- operand->getIntValue());
return createNodeValueInt(- converted->getIntValue());
}
else {
// double
double const value = - operand->getDoubleValue();
double const value = - converted->getDoubleValue();
if (value != value ||
value == HUGE_VAL ||
@ -1108,13 +1152,14 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
// 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 createNodeValueNull();
}
return createNodeValueDouble(value);
}
}
TRI_ASSERT(false);
}
////////////////////////////////////////////////////////////////////////////////
@ -1160,13 +1205,10 @@ AstNode* Ast::optimizeUnaryOperatorLogical (AstNode* node) {
return optimizeNotExpression(node);
}
if (! operand->isBoolValue()) {
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
auto converted = operand->castToBool(this);
// 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);
}
bool const lhsIsConst = lhs->isConstant();
bool const rhsIsConst = rhs->isConstant();
if (lhsIsConst && ! lhs->isBoolValue()) {
// left operand is a constant value, but no boolean
_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
if (lhs->isConstant()) {
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
// left operand is a constant value
if (lhs->isFalse()) {
// return it if it is falsey
return lhs;
}
}
// default: don't optimize
return node;
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
// logical and
if (lhs->getBoolValue()) {
// (true && rhs) => rhs
// left-operand was trueish, now return right operand
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
return lhs;
}
else {
// logical or
if (lhs->getBoolValue()) {
// (true || rhs) => true
return lhs;
// left-operand was falsey, now return right operand
return rhs;
}
// (false || rhs) => rhs
return rhs;
}
// default case
return node;
}
////////////////////////////////////////////////////////////////////////////////
@ -1288,9 +1306,8 @@ AstNode* Ast::optimizeBinaryOperatorRelational (AstNode* node) {
if (rhs->type != NODE_TYPE_LIST &&
(node->type == NODE_TYPE_OPERATOR_BINARY_IN ||
node->type == NODE_TYPE_OPERATOR_BINARY_NIN)) {
// right operand of IN or NOT IN must be a list
_query->registerError(TRI_ERROR_QUERY_LIST_EXPECTED);
return node;
// right operand of IN or NOT IN must be a list, otherwise we return false
return createNodeValueBool(false);
}
if (! lhsIsConst) {
@ -1315,71 +1332,137 @@ AstNode* Ast::optimizeBinaryOperatorArithmetic (AstNode* node) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
bool const lhsIsConst = lhs->isConstant();
bool const rhsIsConst = rhs->isConstant();
if (lhs->isConstant() && 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()) {
// 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;
}
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
if (! lhsIsConst || ! rhsIsConst) {
return node;
}
// now calculate the expression result
double value;
double const l = lhs->getDoubleValue();
double const r = rhs->getDoubleValue();
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) {
value = l + r;
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MINUS) {
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;
if (! useDoublePrecision) {
auto l = left->getIntValue();
auto r = right->getIntValue();
// check if the result would overflow
useDoublePrecision = IsUnsafeAddition<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_MINUS) {
auto left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this);
value = l / r;
}
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MOD) {
if (r == 0.0) {
_query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return node;
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
if (! useDoublePrecision) {
auto l = left->getIntValue();
auto r = right->getIntValue();
// 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);
}
else {
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
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");
}
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;
}
if (! condition->isBoolValue()) {
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
return node;
}
if (condition->getBoolValue()) {
if (condition->isTrue()) {
// condition is always true, replace ternary operation with true part
return truePart;
}
@ -1662,6 +1740,7 @@ AstNode* Ast::createNode (AstNodeType type) {
auto node = new AstNode(type);
try {
// register the node so it gets freed automatically later
_query->addNode(node);
}
catch (...) {

View File

@ -495,6 +495,18 @@ namespace triagens {
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
////////////////////////////////////////////////////////////////////////////////
@ -652,11 +664,29 @@ namespace triagens {
AstNode const* _writeCollection;
////////////////////////////////////////////////////////////////////////////////
/// @brief a singleton NOP node instance
/// @brief a singleton no-op node instance
////////////////////////////////////////////////////////////////////////////////
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
////////////////////////////////////////////////////////////////////////////////

View File

@ -140,6 +140,30 @@ AstNode::AstNode (AstNodeType type)
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
////////////////////////////////////////////////////////////////////////////////
@ -405,6 +429,67 @@ TRI_json_t* AstNode::toJsonValue (TRI_memory_zone_t* zone) const {
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
/// 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;
}
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 '");
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");
}
AstNode* AstNode::castToBool (Ast* ast) {
TRI_ASSERT(type == NODE_TYPE_VALUE ||
type == NODE_TYPE_LIST ||
type == NODE_TYPE_ARRAY);
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);
}
switch (value.type) {
case VALUE_TYPE_NULL:
// null => false
return ast->createNodeValueBool(false);
case VALUE_TYPE_BOOL:
// already a boolean
return this;
case VALUE_TYPE_INT:
return ast->createNodeValueBool(value.value._int != 0);
case VALUE_TYPE_DOUBLE:
return ast->createNodeValueBool(value.value._double != 0.0);
case VALUE_TYPE_STRING:
return ast->createNodeValueBool(*(value.value._string) != '\0');
default: {
}
}
catch (...) {
ret += std::string("Invalid Subnode!");
}
ret += std::string(")");
// fall-through intentional
}
else if (type == NODE_TYPE_LIST) {
// fall-through intentional
}
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
@ -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) {
switch (value.type) {
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');
}
case VALUE_TYPE_NULL:
case VALUE_TYPE_FAIL: {
return false;
}
case VALUE_TYPE_NULL:
return 0;
case VALUE_TYPE_BOOL:
return (value.value._bool ? 1 : 0);
case VALUE_TYPE_INT:
return value.value._int;
case VALUE_TYPE_DOUBLE:
return static_cast<int64_t>(value.value._double);
case VALUE_TYPE_STRING:
return 0;
}
}
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;
}
////////////////////////////////////////////////////////////////////////////////
/// @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
/// expression

View File

@ -51,12 +51,11 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
enum AstNodeValueType {
VALUE_TYPE_FAIL = 0,
VALUE_TYPE_NULL = 1,
VALUE_TYPE_BOOL = 2,
VALUE_TYPE_INT = 3,
VALUE_TYPE_DOUBLE = 4,
VALUE_TYPE_STRING = 5
VALUE_TYPE_NULL = 0,
VALUE_TYPE_BOOL = 1,
VALUE_TYPE_INT = 2,
VALUE_TYPE_DOUBLE = 3,
VALUE_TYPE_STRING = 4
};
////////////////////////////////////////////////////////////////////////////////
@ -154,7 +153,19 @@ namespace triagens {
/// @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
@ -212,6 +223,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
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
@ -221,8 +234,6 @@ namespace triagens {
TRI_json_t* toJson (TRI_memory_zone_t*,
bool) const;
std::string toInfoString (TRI_memory_zone_t* zone) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a JSON representation of the node to the JSON list specified
/// in the first argument
@ -234,9 +245,55 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
/// @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
@ -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 {
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;
}
int64_t getIntValue () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief set the int value of a node
@ -436,17 +475,7 @@ namespace triagens {
/// @brief return the double value of a node
////////////////////////////////////////////////////////////////////////////////
inline 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;
}
double getDoubleValue () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief set the string value of a node

View File

@ -237,14 +237,14 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
TRI_ASSERT(value->isConstant());
if (strcmp(name, "waitForSync") == 0) {
options.waitForSync = value->toBoolean();
options.waitForSync = value->isTrue();
}
else if (strcmp(name, "ignoreErrors") == 0) {
options.ignoreErrors = value->toBoolean();
options.ignoreErrors = value->isTrue();
}
else if (strcmp(name, "keepNull") == 0) {
// 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
TRI_ASSERT(! s->expression()->canThrow());
if (root->toBoolean()) {
if (root->isTrue()) {
// filter is always true
// remove filter node and merge with following node
toUnlink.insert(n);

View File

@ -445,9 +445,9 @@ function executeAndWait (cmd, args) {
if (typeof(res.errorMessage) !== 'undefined') {
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 {
status: false,
status: res.status === 'RUNNING',
message: "irregular termination: " + res.status + " Exit-Code: " + res.exit + errorMessage,
duration: deltaTime
};

View File

@ -28,7 +28,7 @@
var errors = require("internal").errors;
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2;
var getQueryResults = helper.getQueryResultsAQL2;
var assertQueryError = helper.assertQueryError2;
////////////////////////////////////////////////////////////////////////////////
@ -107,13 +107,18 @@ function ahuacatlArithmeticTestSuite () {
/// @brief test unary plus
////////////////////////////////////////////////////////////////////////////////
testUnaryPlusInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +true");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +\"value\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +[ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +{ }");
testUnaryPlusNonNumeric : function () {
assertEqual([ 0 ], getQueryResults("RETURN +null"));
assertEqual([ 1 ], getQueryResults("RETURN +true"));
assertEqual([ 0 ], getQueryResults("RETURN +false"));
assertEqual([ null ], getQueryResults("RETURN +\"value\""));
assertEqual([ 1 ], getQueryResults("RETURN +\"1\""));
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
////////////////////////////////////////////////////////////////////////////////
testUnaryMinusInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -true");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -\"value\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -[ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -{ }");
testUnaryMinusNonNumeric : function () {
assertEqual([ 0 ], getQueryResults("RETURN -null"));
assertEqual([ -1 ], getQueryResults("RETURN -true"));
assertEqual([ 0 ], getQueryResults("RETURN -false"));
assertEqual([ null ], getQueryResults("RETURN -\"value\""));
assertEqual([ -1 ], getQueryResults("RETURN -\"1\""));
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
////////////////////////////////////////////////////////////////////////////////
testBinaryPlusInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + \"0\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ 0 ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + { }");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null + 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false + 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" + 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] + 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] + 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } + 1");
testBinaryPlusNonNumeric : function () {
assertEqual([ 1 ], getQueryResults("RETURN 1 + null"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + false"));
assertEqual([ 2 ], getQueryResults("RETURN 1 + true"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + \"0\""));
assertEqual([ 43 ], getQueryResults("RETURN 1 + \"42\""));
assertEqual([ -16 ], getQueryResults("RETURN 1 + \"-17\""));
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ 0 ]"));
assertEqual([ 5 ], getQueryResults("RETURN 1 + [ 4 ]"));
assertEqual([ -3 ], getQueryResults("RETURN 1 + [ -4 ]"));
assertEqual([ 1 ], getQueryResults("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
////////////////////////////////////////////////////////////////////////////////
testBinaryMinusInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - \"0\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ 0 ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - { }");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null - 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false - 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" - 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] - 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] - 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } - 1");
testBinaryMinusNonNumeric : function () {
assertEqual([ 1 ], getQueryResults("RETURN 1 - null"));
assertEqual([ 1 ], getQueryResults("RETURN 1 - false"));
assertEqual([ 0 ], getQueryResults("RETURN 1 - true"));
assertEqual([ 1 ], getQueryResults("RETURN 1 - \"0\""));
assertEqual([ -41 ], getQueryResults("RETURN 1 - \"42\""));
assertEqual([ 18 ], getQueryResults("RETURN 1 - \"-17\""));
assertEqual([ 1 ], getQueryResults("RETURN 1 - [ ]"));
assertEqual([ 1 ], getQueryResults("RETURN 1 - [ 0 ]"));
assertEqual([ -3 ], getQueryResults("RETURN 1 - [ 4 ]"));
assertEqual([ 5 ], getQueryResults("RETURN 1 - [ -4 ]"));
assertEqual([ 1 ], getQueryResults("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
////////////////////////////////////////////////////////////////////////////////
testBinaryMultiplicationInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * \"0\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ 0 ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * { }");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null * 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false * 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" * 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] * 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] * 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } * 1");
testBinaryMultiplicationNonNumeric : function () {
assertEqual([ 0 ], getQueryResults("RETURN 1 * null"));
assertEqual([ 0 ], getQueryResults("RETURN 1 * false"));
assertEqual([ 1 ], getQueryResults("RETURN 1 * true"));
assertEqual([ 37 ], getQueryResults("RETURN 37 * true"));
assertEqual([ 0 ], getQueryResults("RETURN 1 * \"0\""));
assertEqual([ 42 ], getQueryResults("RETURN 1 * \"42\""));
assertEqual([ -17 ], getQueryResults("RETURN 1 * \"-17\""));
assertEqual([ 0 ], getQueryResults("RETURN 1 * [ ]"));
assertEqual([ 0 ], getQueryResults("RETURN 1 * [ 0 ]"));
assertEqual([ 4 ], getQueryResults("RETURN 1 * [ 4 ]"));
assertEqual([ -4 ], getQueryResults("RETURN 1 * [ -4 ]"));
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
////////////////////////////////////////////////////////////////////////////////
testBinaryDivisionInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / \"0\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ 0 ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / { }");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null / 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false / 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" / 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] / 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] / 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } / 1");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0.0");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / (1 - 1)");
testBinaryDivisionNonNumeric : function () {
assertEqual([ null ], getQueryResults("RETURN 1 / (1 - 1)"));
assertEqual([ null ], getQueryResults("RETURN 1 / 0"));
assertEqual([ null ], getQueryResults("RETURN 1 / 0.0"));
assertEqual([ null ], getQueryResults("RETURN 1 / (1 / 0)"));
assertEqual([ null ], getQueryResults("RETURN 1 / null"));
assertEqual([ null ], getQueryResults("RETURN 1 / false"));
assertEqual([ 1 ], getQueryResults("RETURN 1 / true"));
assertEqual([ 37 ], getQueryResults("RETURN 37 / true"));
assertEqual([ null ], getQueryResults("RETURN 1 / \"0\""));
assertEqual([ 0.25 ], getQueryResults("RETURN 1 / \"4\""));
assertEqual([ -2 ], getQueryResults("RETURN 34 / \"-17\""));
assertEqual([ null ], getQueryResults("RETURN 1 / [ ]"));
assertEqual([ null ], getQueryResults("RETURN 1 / [ 0 ]"));
assertEqual([ 0.25 ], getQueryResults("RETURN 1 / [ 4 ]"));
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 () {
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % null");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % false");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % \"0\"");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ 0 ]");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % { }");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null % 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false % 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" % 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] % 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] % 1");
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } % 1");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0.0");
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % (1 - 1)");
assertEqual([ null ], getQueryResults("RETURN 1 % (1 - 1)"));
assertEqual([ null ], getQueryResults("RETURN 1 % 0"));
assertEqual([ null ], getQueryResults("RETURN 1 % 0.0"));
assertEqual([ null ], getQueryResults("RETURN 1 % (1 / 0)"));
assertEqual([ null ], getQueryResults("RETURN 1 % null"));
assertEqual([ null ], getQueryResults("RETURN 1 % false"));
assertEqual([ 0 ], getQueryResults("RETURN 1 % true"));
assertEqual([ 0 ], getQueryResults("RETURN 37 % true"));
assertEqual([ null ], getQueryResults("RETURN 1 % \"0\""));
assertEqual([ 1 ], getQueryResults("RETURN 1 % \"4\""));
assertEqual([ 3 ], getQueryResults("RETURN 7 % \"4\""));
assertEqual([ 3 ], getQueryResults("RETURN 7 % \"-4\""));
assertEqual([ 0 ], getQueryResults("RETURN 34 % \"-17\""));
assertEqual([ 1 ], getQueryResults("RETURN 35 % \"17\""));
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 () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 null RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN false RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN 1.2 RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN '' RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN {} RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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: false }));
assertEqual([ ], getQueryResultsAQL2("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: "" }));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: { } }));
},
////////////////////////////////////////////////////////////////////////////////
@ -428,16 +428,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testInvalidNotIn : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 null RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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 1.2 RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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"));
assertEqual([ ], getQueryResultsAQL2("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: false }));
assertEqual([ ], getQueryResultsAQL2("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: "" }));
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: { } }));
},
////////////////////////////////////////////////////////////////////////////////
@ -445,16 +445,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testInvalidInCollection : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 null RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN false RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN 1.2 RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN '' RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN {} RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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: false }));
assertEqual([ ], getQueryResultsAQL2("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: "" }));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: { } }));
},
////////////////////////////////////////////////////////////////////////////////
@ -462,16 +462,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testInvalidNotInCollection : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 null RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN false RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN 1.2 RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN '' RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN {} RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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: false }));
assertEqual([ ], getQueryResultsAQL2("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: "" }));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: { } }));
},
////////////////////////////////////////////////////////////////////////////////
@ -479,16 +479,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
////////////////////////////////////////////////////////////////////////////////
testInvalidInCollectionIndex : function () {
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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");
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 });
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "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 null RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN false RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN 1.2 RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN '' RETURN i"));
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN {} RETURN i"));
assertEqual([ ], getQueryResultsAQL2("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: false }));
assertEqual([ ], getQueryResultsAQL2("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: "" }));
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 jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2;
var getQueryResults = helper.getQueryResultsAQL2;
var assertQueryError = helper.assertQueryError2;
////////////////////////////////////////////////////////////////////////////////
@ -167,14 +167,19 @@ function ahuacatlTernaryTestSuite () {
/// @brief test ternary with non-boolean condition
////////////////////////////////////////////////////////////////////////////////
testTernaryInvalid : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN 1 ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN null ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4) ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4 - 3) ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN \"true\" ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN [ ] ? 2 : 3");
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN { } ? 2 : 3");
testTernaryNonBoolean : function () {
assertEqual([ 2 ], getQueryResults("RETURN 1 ? 2 : 3"));
assertEqual([ 3 ], getQueryResults("RETURN 0 ? 2 : 3"));
assertEqual([ 3 ], getQueryResults("RETURN null ? 2 : 3"));
assertEqual([ 3 ], getQueryResults("RETURN false ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN true ? 2 : 3"));
assertEqual([ 2 ], getQueryResults("RETURN (4) ? 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
///
@ -421,7 +424,7 @@ function TaskSuite () {
assertEqual(10, task.offset);
assertEqual("_system", task.database);
t = getTasks();
var t = getTasks();
assertEqual(1, t.length);
internal.wait(2);
@ -456,7 +459,7 @@ function TaskSuite () {
assertEqual(2, task.offset);
assertEqual("_system", task.database);
t = getTasks();
var t = getTasks();
assertEqual(1, t.length);
internal.wait(5);
@ -492,7 +495,7 @@ function TaskSuite () {
internal.wait(1);
t = getTasks();
var t = getTasks();
assertEqual(0, t.length);
internal.wait(5);
@ -526,7 +529,7 @@ function TaskSuite () {
assertEqual(5, task.offset);
assertEqual("_system", task.database);
t = getTasks();
var t = getTasks();
assertEqual(1, t.length);
internal.wait(15);
@ -572,7 +575,7 @@ function TaskSuite () {
assertEqual(0, db[cn].count());
assertEqual(0, db[cn].byExample({ value: 23 }).toArray().length);
t = getTasks();
var t = getTasks();
assertEqual(0, t.length);
},

View File

@ -48,7 +48,7 @@
#include <sys/wait.h>
#endif
#ifdef WIN32
#ifdef _WIN32
#include <Psapi.h>
#include <TlHelp32.h>
#endif
@ -220,15 +220,6 @@ static bool CreatePipes (int* pipe_server_to_child,
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
////////////////////////////////////////////////////////////////////////////////
@ -1280,17 +1271,6 @@ void TRI_InitialiseProcess (int argc, char* argv[]) {
TRI_InitVectorPointer(&ExternalProcesses, TRI_CORE_MEM_ZONE);
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
}
////////////////////////////////////////////////////////////////////////////////