diff --git a/CHANGELOG b/CHANGELOG index 6f0d72cac2..7809421ad3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/arangod/Aql/Arithmetic.h b/arangod/Aql/Arithmetic.h new file mode 100644 index 0000000000..74754846d9 --- /dev/null +++ b/arangod/Aql/Arithmetic.h @@ -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 + bool IsUnsafeAddition (T l, T r) { + return ((r > 0 && l > std::numeric_limits::max() - r) || + (r < 0 && l < std::numeric_limits::min() - r)); + } + + template + bool IsUnsafeSubtraction (T l, T r) { + return ((r > 0 && l < std::numeric_limits::min() + r) || (r < 0 && l > std::numeric_limits::max() + r)); + } + + template + bool IsUnsafeMultiplication (T l, T r) { + if (l > 0) { + if (r > 0) { + if (l > (std::numeric_limits::max() / r)) { + return true; + } + } + else { + if (r < (std::numeric_limits::min() / l)) { + return true; + } + } + } + else { + if (r > 0) { + if (l < (std::numeric_limits::min() / r)) { + return true; + } + } + else { + if ( (l != 0) && (r < (std::numeric_limits::max() / l))) { + return true; + } + } + } + + return false; + } + + template + bool IsUnsafeDivision (T l, T r) { + return (l == std::numeric_limits::min() && r == -1); + } + + } +} + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: + diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 3b1515c61a..d7d0594b84 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -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(&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(&TrueNode); + } + return const_cast(&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(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(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(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(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(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 (...) { diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index 2d581d8d01..ca5474aeab 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -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 //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index 6e597ef1fb..00e80f2be8 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -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(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(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(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(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(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(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 diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index 5a71abc87d..1afaf2c7a9 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -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(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(value.value._int); - } - - return value.value._double; - } + double getDoubleValue () const; //////////////////////////////////////////////////////////////////////////////// /// @brief set the string value of a node diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index 7e0b8a58b4..a2f74213ee 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -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(); } } } diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index ea419e9071..b445fee317 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -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); diff --git a/js/server/modules/org/arangodb/testing.js b/js/server/modules/org/arangodb/testing.js index 74411f6030..323afa07b4 100644 --- a/js/server/modules/org/arangodb/testing.js +++ b/js/server/modules/org/arangodb/testing.js @@ -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 }; diff --git a/js/server/tests/aql-arithmetic.js b/js/server/tests/aql-arithmetic.js index b4130c79eb..cdc84f741a 100644 --- a/js/server/tests/aql-arithmetic.js +++ b/js/server/tests/aql-arithmetic.js @@ -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")); }, //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/aql-queries-optimiser-in.js b/js/server/tests/aql-queries-optimiser-in.js index 8226f6993a..fd896cecc4 100644 --- a/js/server/tests/aql-queries-optimiser-in.js +++ b/js/server/tests/aql-queries-optimiser-in.js @@ -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: { } })); }, //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/aql-ternary.js b/js/server/tests/aql-ternary.js index b42edf64af..78e442ac60 100644 --- a/js/server/tests/aql-ternary.js +++ b/js/server/tests/aql-ternary.js @@ -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")); } }; diff --git a/js/server/tests/shell-tasks.js b/js/server/tests/shell-tasks-timecritical.js similarity index 98% rename from js/server/tests/shell-tasks.js rename to js/server/tests/shell-tasks-timecritical.js index d4936877f1..4eaa239edd 100644 --- a/js/server/tests/shell-tasks.js +++ b/js/server/tests/shell-tasks-timecritical.js @@ -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); }, diff --git a/lib/Basics/process-utils.cpp b/lib/Basics/process-utils.cpp index 5353ae4a18..f4abf7efa5 100644 --- a/lib/Basics/process-utils.cpp +++ b/lib/Basics/process-utils.cpp @@ -48,7 +48,7 @@ #include #endif -#ifdef WIN32 +#ifdef _WIN32 #include #include #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 } ////////////////////////////////////////////////////////////////////////////////