mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of ssh://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
362dc083cc
10
CHANGELOG
10
CHANGELOG
|
@ -129,7 +129,13 @@ v2.3.0 (XXXX-XX-XX)
|
||||||
storing JavaScript date objects in the database in a sensible manner.
|
storing JavaScript date objects in the database in a sensible manner.
|
||||||
|
|
||||||
|
|
||||||
v2.2.x (????-??-??)
|
v2.2.6 (XXXX-XX-XX)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* fixed issue #972: Compilation Issue
|
||||||
|
|
||||||
|
|
||||||
|
v2.2.5 (2014-10-09)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
* fixed issue #961: allow non-JSON values in undocument request bodies
|
* fixed issue #961: allow non-JSON values in undocument request bodies
|
||||||
|
@ -140,7 +146,7 @@ v2.2.x (????-??-??)
|
||||||
problems after collection rename operations
|
problems after collection rename operations
|
||||||
|
|
||||||
|
|
||||||
v2.2.4 (2014-XX-XX)
|
v2.2.4 (2014-10-01)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
* fixed accessing `_from` and `_to` attributes in `collection.byExample` and
|
* fixed accessing `_from` and `_to` attributes in `collection.byExample` and
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "Aql/Ast.h"
|
#include "Aql/Ast.h"
|
||||||
|
#include "Aql/Arithmetic.h"
|
||||||
#include "Aql/Collection.h"
|
#include "Aql/Collection.h"
|
||||||
#include "Aql/Executor.h"
|
#include "Aql/Executor.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
|
@ -41,10 +42,28 @@ using namespace triagens::aql;
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief initialise a singleton NOP node instance
|
/// @brief initialise a singleton no-op node instance
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode const Ast::NopNode = { NODE_TYPE_NOP };
|
AstNode const Ast::NopNode{ NODE_TYPE_NOP };
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief initialise a singleton null node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode const Ast::NullNode{ NODE_TYPE_VALUE, VALUE_TYPE_NULL };
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief initialise a singleton false node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode const Ast::FalseNode{ false };
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief initialise a singleton true node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode const Ast::TrueNode{ true };
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief inverse comparison operators
|
/// @brief inverse comparison operators
|
||||||
|
@ -587,10 +606,9 @@ AstNode* Ast::createNodeIterator (char const* variableName,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* Ast::createNodeValueNull () {
|
AstNode* Ast::createNodeValueNull () {
|
||||||
AstNode* node = createNode(NODE_TYPE_VALUE);
|
// return a pointer to the singleton null node
|
||||||
node->setValueType(VALUE_TYPE_NULL);
|
// note: this node is never registered nor freed
|
||||||
|
return const_cast<AstNode*>(&NullNode);
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -598,11 +616,12 @@ AstNode* Ast::createNodeValueNull () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode* Ast::createNodeValueBool (bool value) {
|
AstNode* Ast::createNodeValueBool (bool value) {
|
||||||
AstNode* node = createNode(NODE_TYPE_VALUE);
|
// return a pointer to the singleton bool nodes
|
||||||
node->setValueType(VALUE_TYPE_BOOL);
|
// note: these nodes are never registered nor freed
|
||||||
node->setBoolValue(value);
|
if (value) {
|
||||||
|
return const_cast<AstNode*>(&TrueNode);
|
||||||
return node;
|
}
|
||||||
|
return const_cast<AstNode*>(&FalseNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1034,6 +1053,32 @@ AstNode* Ast::clone (AstNode const* node) {
|
||||||
// --SECTION-- private methods
|
// --SECTION-- private methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a number node for an arithmetic result, integer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* Ast::createArithmeticResultNode (int64_t value) {
|
||||||
|
return createNodeValueInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a number node for an arithmetic result, double
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* Ast::createArithmeticResultNode (double value) {
|
||||||
|
if (value != value ||
|
||||||
|
value == HUGE_VAL ||
|
||||||
|
value == - HUGE_VAL) {
|
||||||
|
// IEEE754 NaN values have an interesting property that we can exploit...
|
||||||
|
// if the architecture does not use IEEE754 values then this shouldn't do
|
||||||
|
// any harm either
|
||||||
|
// TODO: log an error: _query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
|
||||||
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createNodeValueDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief executes an expression with constant parameters
|
/// @brief executes an expression with constant parameters
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1080,27 +1125,26 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! operand->isNumericValue()) {
|
// operand is a constant, now convert it into a number
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
|
auto converted = operand->castToNumber(this);
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_ASSERT(operand->value.type == VALUE_TYPE_INT ||
|
if (converted->isNullValue()) {
|
||||||
operand->value.type == VALUE_TYPE_DOUBLE);
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
if (node->type == NODE_TYPE_OPERATOR_UNARY_PLUS) {
|
if (node->type == NODE_TYPE_OPERATOR_UNARY_PLUS) {
|
||||||
// + number => number
|
// + number => number
|
||||||
return operand;
|
return converted;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// - number
|
// - number
|
||||||
if (operand->value.type == VALUE_TYPE_INT) {
|
if (converted->value.type == VALUE_TYPE_INT) {
|
||||||
// int64
|
// int64
|
||||||
return createNodeValueInt(- operand->getIntValue());
|
return createNodeValueInt(- converted->getIntValue());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// double
|
// double
|
||||||
double const value = - operand->getDoubleValue();
|
double const value = - converted->getDoubleValue();
|
||||||
|
|
||||||
if (value != value ||
|
if (value != value ||
|
||||||
value == HUGE_VAL ||
|
value == HUGE_VAL ||
|
||||||
|
@ -1108,13 +1152,14 @@ AstNode* Ast::optimizeUnaryOperatorArithmetic (AstNode* node) {
|
||||||
// IEEE754 NaN values have an interesting property that we can exploit...
|
// IEEE754 NaN values have an interesting property that we can exploit...
|
||||||
// if the architecture does not use IEEE754 values then this shouldn't do
|
// if the architecture does not use IEEE754 values then this shouldn't do
|
||||||
// any harm either
|
// any harm either
|
||||||
_query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
|
return createNodeValueNull();
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return createNodeValueDouble(value);
|
return createNodeValueDouble(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1160,13 +1205,10 @@ AstNode* Ast::optimizeUnaryOperatorLogical (AstNode* node) {
|
||||||
return optimizeNotExpression(node);
|
return optimizeNotExpression(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! operand->isBoolValue()) {
|
auto converted = operand->castToBool(this);
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace unary negation operation with result of negation
|
// replace unary negation operation with result of negation
|
||||||
return createNodeValueBool(! operand->getBoolValue());
|
return createNodeValueBool(! converted->getBoolValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1186,55 +1228,31 @@ AstNode* Ast::optimizeBinaryOperatorLogical (AstNode* node) {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const lhsIsConst = lhs->isConstant();
|
if (lhs->isConstant()) {
|
||||||
bool const rhsIsConst = rhs->isConstant();
|
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
|
||||||
|
// left operand is a constant value
|
||||||
if (lhsIsConst && ! lhs->isBoolValue()) {
|
if (lhs->isFalse()) {
|
||||||
// left operand is a constant value, but no boolean
|
// return it if it is falsey
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhsIsConst && ! rhs->isBoolValue()) {
|
|
||||||
// right operand is a constant value, but no boolean
|
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! lhsIsConst) {
|
|
||||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
|
|
||||||
if (rhsIsConst && ! rhs->getBoolValue()) {
|
|
||||||
// (lhs || false) => lhs
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// default: don't optimize
|
// left-operand was trueish, now return right operand
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
|
|
||||||
// logical and
|
|
||||||
|
|
||||||
if (lhs->getBoolValue()) {
|
|
||||||
// (true && rhs) => rhs
|
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
else if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
|
||||||
|
// left operand is a constant value
|
||||||
|
if (lhs->isTrue()) {
|
||||||
|
// return it if it is trueish
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
// (false && rhs) => false
|
// left-operand was falsey, now return right operand
|
||||||
return lhs;
|
return rhs;
|
||||||
}
|
|
||||||
else {
|
|
||||||
// logical or
|
|
||||||
|
|
||||||
if (lhs->getBoolValue()) {
|
|
||||||
// (true || rhs) => true
|
|
||||||
return lhs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// (false || rhs) => rhs
|
|
||||||
return rhs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default case
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1288,9 +1306,8 @@ AstNode* Ast::optimizeBinaryOperatorRelational (AstNode* node) {
|
||||||
if (rhs->type != NODE_TYPE_LIST &&
|
if (rhs->type != NODE_TYPE_LIST &&
|
||||||
(node->type == NODE_TYPE_OPERATOR_BINARY_IN ||
|
(node->type == NODE_TYPE_OPERATOR_BINARY_IN ||
|
||||||
node->type == NODE_TYPE_OPERATOR_BINARY_NIN)) {
|
node->type == NODE_TYPE_OPERATOR_BINARY_NIN)) {
|
||||||
// right operand of IN or NOT IN must be a list
|
// right operand of IN or NOT IN must be a list, otherwise we return false
|
||||||
_query->registerError(TRI_ERROR_QUERY_LIST_EXPECTED);
|
return createNodeValueBool(false);
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! lhsIsConst) {
|
if (! lhsIsConst) {
|
||||||
|
@ -1315,71 +1332,137 @@ AstNode* Ast::optimizeBinaryOperatorArithmetic (AstNode* node) {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const lhsIsConst = lhs->isConstant();
|
if (lhs->isConstant() && rhs->isConstant()) {
|
||||||
bool const rhsIsConst = rhs->isConstant();
|
// now calculate the expression result
|
||||||
|
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) {
|
||||||
|
// TODO: add string concatenation
|
||||||
|
auto left = lhs->castToNumber(this);
|
||||||
|
auto right = rhs->castToNumber(this);
|
||||||
|
|
||||||
if (lhsIsConst && ! lhs->isNumericValue()) {
|
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
|
||||||
// lhs is not a number
|
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhsIsConst && ! rhs->isNumericValue()) {
|
|
||||||
// rhs is not a number
|
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! lhsIsConst || ! rhsIsConst) {
|
if (! useDoublePrecision) {
|
||||||
return node;
|
auto l = left->getIntValue();
|
||||||
}
|
auto r = right->getIntValue();
|
||||||
|
// check if the result would overflow
|
||||||
// now calculate the expression result
|
useDoublePrecision = IsUnsafeAddition<int64_t>(l, r);
|
||||||
|
|
||||||
double value;
|
if (! useDoublePrecision) {
|
||||||
double const l = lhs->getDoubleValue();
|
// can calculate using integers
|
||||||
double const r = rhs->getDoubleValue();
|
return createArithmeticResultNode(l + r);
|
||||||
|
}
|
||||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) {
|
}
|
||||||
value = l + r;
|
|
||||||
}
|
// must use double precision
|
||||||
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MINUS) {
|
return createArithmeticResultNode(left->getDoubleValue() + right->getDoubleValue());
|
||||||
value = l - r;
|
|
||||||
}
|
|
||||||
else if (node->type == NODE_TYPE_OPERATOR_BINARY_TIMES) {
|
|
||||||
value = l * r;
|
|
||||||
}
|
|
||||||
else if (node->type == NODE_TYPE_OPERATOR_BINARY_DIV) {
|
|
||||||
if (r == 0.0) {
|
|
||||||
_query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MINUS) {
|
||||||
|
auto left = lhs->castToNumber(this);
|
||||||
|
auto right = rhs->castToNumber(this);
|
||||||
|
|
||||||
value = l / r;
|
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
|
||||||
}
|
|
||||||
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MOD) {
|
if (! useDoublePrecision) {
|
||||||
if (r == 0.0) {
|
auto l = left->getIntValue();
|
||||||
_query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
auto r = right->getIntValue();
|
||||||
return node;
|
// check if the result would overflow
|
||||||
|
useDoublePrecision = IsUnsafeSubtraction<int64_t>(l, r);
|
||||||
|
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
// can calculate using integers
|
||||||
|
return createArithmeticResultNode(l - r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// must use double precision
|
||||||
|
return createArithmeticResultNode(left->getDoubleValue() - right->getDoubleValue());
|
||||||
}
|
}
|
||||||
|
else if (node->type == NODE_TYPE_OPERATOR_BINARY_TIMES) {
|
||||||
|
auto left = lhs->castToNumber(this);
|
||||||
|
auto right = rhs->castToNumber(this);
|
||||||
|
|
||||||
value = fmod(l, r);
|
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
|
||||||
}
|
|
||||||
else {
|
if (! useDoublePrecision) {
|
||||||
|
auto l = left->getIntValue();
|
||||||
|
auto r = right->getIntValue();
|
||||||
|
// check if the result would overflow
|
||||||
|
useDoublePrecision = IsUnsafeMultiplication<int64_t>(l, r);
|
||||||
|
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
// can calculate using integers
|
||||||
|
return createArithmeticResultNode(l * r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// must use double precision
|
||||||
|
return createArithmeticResultNode(left->getDoubleValue() * right->getDoubleValue());
|
||||||
|
}
|
||||||
|
else if (node->type == NODE_TYPE_OPERATOR_BINARY_DIV) {
|
||||||
|
auto left = lhs->castToNumber(this);
|
||||||
|
auto right = rhs->castToNumber(this);
|
||||||
|
|
||||||
|
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
auto l = left->getIntValue();
|
||||||
|
auto r = right->getIntValue();
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
||||||
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the result would overflow
|
||||||
|
useDoublePrecision = (IsUnsafeDivision<int64_t>(l, r) || r < -1 || r > 1);
|
||||||
|
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
// can calculate using integers
|
||||||
|
return createArithmeticResultNode(l / r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right->getDoubleValue() == 0.0) {
|
||||||
|
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
||||||
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createArithmeticResultNode(left->getDoubleValue() / right->getDoubleValue());
|
||||||
|
}
|
||||||
|
else if (node->type == NODE_TYPE_OPERATOR_BINARY_MOD) {
|
||||||
|
auto left = lhs->castToNumber(this);
|
||||||
|
auto right = rhs->castToNumber(this);
|
||||||
|
|
||||||
|
bool useDoublePrecision = (left->isDoubleValue() || right->isDoubleValue());
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
auto l = left->getIntValue();
|
||||||
|
auto r = right->getIntValue();
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
||||||
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the result would overflow
|
||||||
|
useDoublePrecision = IsUnsafeDivision<int64_t>(l, r);
|
||||||
|
|
||||||
|
if (! useDoublePrecision) {
|
||||||
|
// can calculate using integers
|
||||||
|
return createArithmeticResultNode(l % r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right->getDoubleValue() == 0.0) {
|
||||||
|
// TODO: log an error _query->registerError(TRI_ERROR_QUERY_DIVISION_BY_ZERO);
|
||||||
|
return createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createArithmeticResultNode(fmod(left->getDoubleValue(), right->getDoubleValue()));
|
||||||
|
}
|
||||||
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid operator");
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value != value ||
|
|
||||||
value == HUGE_VAL ||
|
|
||||||
value == - HUGE_VAL) {
|
|
||||||
// IEEE754 NaN values have an interesting property that we can exploit...
|
|
||||||
// if the architecture does not use IEEE754 values then this shouldn't do
|
|
||||||
// any harm either
|
|
||||||
_query->registerError(TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return createNodeValueDouble(value);
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1407,12 +1490,7 @@ AstNode* Ast::optimizeTernaryOperator (AstNode* node) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! condition->isBoolValue()) {
|
if (condition->isTrue()) {
|
||||||
_query->registerError(TRI_ERROR_QUERY_INVALID_LOGICAL_VALUE);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (condition->getBoolValue()) {
|
|
||||||
// condition is always true, replace ternary operation with true part
|
// condition is always true, replace ternary operation with true part
|
||||||
return truePart;
|
return truePart;
|
||||||
}
|
}
|
||||||
|
@ -1662,6 +1740,7 @@ AstNode* Ast::createNode (AstNodeType type) {
|
||||||
auto node = new AstNode(type);
|
auto node = new AstNode(type);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// register the node so it gets freed automatically later
|
||||||
_query->addNode(node);
|
_query->addNode(node);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
|
|
@ -495,6 +495,18 @@ namespace triagens {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a number node for an arithmetic result, integer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* createArithmeticResultNode (int64_t);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a number node for an arithmetic result, double
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* createArithmeticResultNode (double);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief executes an expression with constant parameters
|
/// @brief executes an expression with constant parameters
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -652,11 +664,29 @@ namespace triagens {
|
||||||
AstNode const* _writeCollection;
|
AstNode const* _writeCollection;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief a singleton NOP node instance
|
/// @brief a singleton no-op node instance
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static AstNode const NopNode;
|
static AstNode const NopNode;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief a singleton null node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static AstNode const NullNode;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief a singleton false node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static AstNode const FalseNode;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief a singleton true node instance
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static AstNode const TrueNode;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief inverse comparison operators
|
/// @brief inverse comparison operators
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -140,6 +140,30 @@ AstNode::AstNode (AstNodeType type)
|
||||||
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
|
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a node, with defining a value type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode::AstNode (AstNodeType type,
|
||||||
|
AstNodeValueType valueType)
|
||||||
|
: AstNode(type) {
|
||||||
|
|
||||||
|
value.type = valueType;
|
||||||
|
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a boolean node, with defining a value
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode::AstNode (bool v)
|
||||||
|
: AstNode(NODE_TYPE_VALUE) {
|
||||||
|
|
||||||
|
value.type = VALUE_TYPE_BOOL;
|
||||||
|
value.value._bool = v;
|
||||||
|
TRI_InitVectorPointer(&members, TRI_UNKNOWN_MEM_ZONE);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create the node from JSON
|
/// @brief create the node from JSON
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -405,6 +429,67 @@ TRI_json_t* AstNode::toJsonValue (TRI_memory_zone_t* zone) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AstNode::toInfoString (TRI_memory_zone_t* zone) const {
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
ret += std::string(" of Type '");
|
||||||
|
ret += getTypeString();
|
||||||
|
ret += std::string("' ");
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_COLLECTION ||
|
||||||
|
type == NODE_TYPE_PARAMETER ||
|
||||||
|
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||||
|
type == NODE_TYPE_ARRAY_ELEMENT ||
|
||||||
|
type == NODE_TYPE_FCALL_USER) {
|
||||||
|
// dump "name" of node
|
||||||
|
ret += std::string(" by Name ");
|
||||||
|
ret += getStringValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_FCALL) {
|
||||||
|
auto func = static_cast<Function*>(getData());
|
||||||
|
ret += std::string(" by Name '");
|
||||||
|
ret += func->externalName;
|
||||||
|
ret += std::string("' with Parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_VALUE) {
|
||||||
|
// dump value of "value" node
|
||||||
|
ret += std::string(" with Value(s) ");
|
||||||
|
/// TODO: auto v = toJsonValue(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_VARIABLE ||
|
||||||
|
type == NODE_TYPE_REFERENCE) {
|
||||||
|
auto variable = static_cast<Variable*>(getData());
|
||||||
|
ret += std::string(" by Name(");
|
||||||
|
ret += variable->name;
|
||||||
|
ret += std::string(") ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump sub-nodes
|
||||||
|
size_t const n = members._length;
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
ret += std::string("(");
|
||||||
|
try {
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto member = getMember(i);
|
||||||
|
if (member != nullptr && member->type != NODE_TYPE_NOP) {
|
||||||
|
ret += member->toInfoString(zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
ret += std::string("Invalid Subnode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return a JSON representation of the node
|
/// @brief return a JSON representation of the node
|
||||||
/// the caller is responsible for freeing the JSON later
|
/// the caller is responsible for freeing the JSON later
|
||||||
|
@ -497,67 +582,103 @@ TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone,
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AstNode::toInfoString (TRI_memory_zone_t* zone) const {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
std::string ret;
|
/// @brief convert the node's value to a boolean value
|
||||||
|
/// this may create a new node or return the node itself if it is already a
|
||||||
|
/// boolean value node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ret += std::string(" of Type '");
|
AstNode* AstNode::castToBool (Ast* ast) {
|
||||||
ret += getTypeString();
|
TRI_ASSERT(type == NODE_TYPE_VALUE ||
|
||||||
ret += std::string("' ");
|
type == NODE_TYPE_LIST ||
|
||||||
|
type == NODE_TYPE_ARRAY);
|
||||||
if (type == NODE_TYPE_COLLECTION ||
|
|
||||||
type == NODE_TYPE_PARAMETER ||
|
|
||||||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
|
||||||
type == NODE_TYPE_ARRAY_ELEMENT ||
|
|
||||||
type == NODE_TYPE_FCALL_USER) {
|
|
||||||
// dump "name" of node
|
|
||||||
ret += std::string(" by Name ");
|
|
||||||
ret += getStringValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == NODE_TYPE_FCALL) {
|
|
||||||
auto func = static_cast<Function*>(getData());
|
|
||||||
ret += std::string(" by Name '");
|
|
||||||
ret += func->externalName;
|
|
||||||
ret += std::string("' with Parameters");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == NODE_TYPE_VALUE) {
|
if (type == NODE_TYPE_VALUE) {
|
||||||
// dump value of "value" node
|
switch (value.type) {
|
||||||
ret += std::string(" with Value(s) ");
|
case VALUE_TYPE_NULL:
|
||||||
/// TODO: auto v = toJsonValue(zone);
|
// null => false
|
||||||
}
|
return ast->createNodeValueBool(false);
|
||||||
|
case VALUE_TYPE_BOOL:
|
||||||
if (type == NODE_TYPE_VARIABLE ||
|
// already a boolean
|
||||||
type == NODE_TYPE_REFERENCE) {
|
return this;
|
||||||
auto variable = static_cast<Variable*>(getData());
|
case VALUE_TYPE_INT:
|
||||||
ret += std::string(" by Name(");
|
return ast->createNodeValueBool(value.value._int != 0);
|
||||||
ret += variable->name;
|
case VALUE_TYPE_DOUBLE:
|
||||||
ret += std::string(") ");
|
return ast->createNodeValueBool(value.value._double != 0.0);
|
||||||
}
|
case VALUE_TYPE_STRING:
|
||||||
|
return ast->createNodeValueBool(*(value.value._string) != '\0');
|
||||||
// dump sub-nodes
|
default: {
|
||||||
size_t const n = members._length;
|
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
ret += std::string("(");
|
|
||||||
try {
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
auto member = getMember(i);
|
|
||||||
if (member != nullptr && member->type != NODE_TYPE_NOP) {
|
|
||||||
ret += member->toInfoString(zone);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
// fall-through intentional
|
||||||
ret += std::string("Invalid Subnode!");
|
}
|
||||||
}
|
else if (type == NODE_TYPE_LIST) {
|
||||||
|
// fall-through intentional
|
||||||
ret += std::string(")");
|
}
|
||||||
|
else if (type == NODE_TYPE_ARRAY) {
|
||||||
|
// fall-through intentional
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ast->createNodeValueBool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief convert the node's value to a number value
|
||||||
|
/// this may create a new node or return the node itself if it is already a
|
||||||
|
/// numeric value node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* AstNode::castToNumber (Ast* ast) {
|
||||||
|
TRI_ASSERT(type == NODE_TYPE_VALUE ||
|
||||||
|
type == NODE_TYPE_LIST ||
|
||||||
|
type == NODE_TYPE_ARRAY);
|
||||||
|
|
||||||
|
if (type == NODE_TYPE_VALUE) {
|
||||||
|
switch (value.type) {
|
||||||
|
case VALUE_TYPE_NULL:
|
||||||
|
// null => 0
|
||||||
|
return ast->createNodeValueInt(0);
|
||||||
|
case VALUE_TYPE_BOOL:
|
||||||
|
// false => 0, true => 1
|
||||||
|
return ast->createNodeValueInt(value.value._bool ? 1 : 0);
|
||||||
|
case VALUE_TYPE_INT:
|
||||||
|
case VALUE_TYPE_DOUBLE:
|
||||||
|
// already numeric!
|
||||||
|
return this;
|
||||||
|
case VALUE_TYPE_STRING:
|
||||||
|
try {
|
||||||
|
// try converting string to number
|
||||||
|
double v = std::stod(value.value._string);
|
||||||
|
return ast->createNodeValueDouble(v);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// conversion failed
|
||||||
|
}
|
||||||
|
// fall-through intentional
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fall-through intentional
|
||||||
|
}
|
||||||
|
else if (type == NODE_TYPE_LIST) {
|
||||||
|
size_t const n = numMembers();
|
||||||
|
if (n == 0) {
|
||||||
|
// [ ] => 0
|
||||||
|
return ast->createNodeValueInt(0);
|
||||||
|
}
|
||||||
|
else if (n == 1) {
|
||||||
|
auto member = getMember(0);
|
||||||
|
// convert only member to number
|
||||||
|
return member->castToNumber(ast);
|
||||||
|
}
|
||||||
|
// fall-through intentional
|
||||||
|
}
|
||||||
|
else if (type == NODE_TYPE_ARRAY) {
|
||||||
|
// fall-through intentional
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast->createNodeValueNull();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief adds a JSON representation of the node to the JSON list specified
|
/// @brief adds a JSON representation of the node to the JSON list specified
|
||||||
|
@ -579,34 +700,84 @@ void AstNode::toJson (TRI_json_t* json,
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief convert the node's value to a boolean value
|
/// @brief get the integer value of a node, provided the node is a value node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool AstNode::toBoolean () const {
|
int64_t AstNode::getIntValue () const {
|
||||||
if (type == NODE_TYPE_VALUE) {
|
if (type == NODE_TYPE_VALUE) {
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case VALUE_TYPE_BOOL: {
|
case VALUE_TYPE_NULL:
|
||||||
return value.value._bool;
|
return 0;
|
||||||
}
|
case VALUE_TYPE_BOOL:
|
||||||
case VALUE_TYPE_INT: {
|
return (value.value._bool ? 1 : 0);
|
||||||
return (value.value._int != 0);
|
case VALUE_TYPE_INT:
|
||||||
}
|
return value.value._int;
|
||||||
case VALUE_TYPE_DOUBLE: {
|
case VALUE_TYPE_DOUBLE:
|
||||||
return value.value._double != 0.0;
|
return static_cast<int64_t>(value.value._double);
|
||||||
}
|
case VALUE_TYPE_STRING:
|
||||||
case VALUE_TYPE_STRING: {
|
return 0;
|
||||||
return (*value.value._string != '\0');
|
|
||||||
}
|
|
||||||
case VALUE_TYPE_NULL:
|
|
||||||
case VALUE_TYPE_FAIL: {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief get the double value of a node, provided the node is a value node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
double AstNode::getDoubleValue () const {
|
||||||
|
if (type == NODE_TYPE_VALUE) {
|
||||||
|
switch (value.type) {
|
||||||
|
case VALUE_TYPE_NULL:
|
||||||
|
return 0.0;
|
||||||
|
case VALUE_TYPE_BOOL:
|
||||||
|
return (value.value._bool ? 1.0 : 0.0);
|
||||||
|
case VALUE_TYPE_INT:
|
||||||
|
return static_cast<double>(value.value._int);
|
||||||
|
case VALUE_TYPE_DOUBLE:
|
||||||
|
return value.value._double;
|
||||||
|
case VALUE_TYPE_STRING:
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the node value is trueish
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool AstNode::isTrue () const {
|
||||||
|
if (type == NODE_TYPE_VALUE) {
|
||||||
|
switch (value.type) {
|
||||||
|
case VALUE_TYPE_NULL:
|
||||||
|
return false;
|
||||||
|
case VALUE_TYPE_BOOL:
|
||||||
|
return value.value._bool;
|
||||||
|
case VALUE_TYPE_INT:
|
||||||
|
return (value.value._int != 0);
|
||||||
|
case VALUE_TYPE_DOUBLE:
|
||||||
|
return value.value._double != 0.0;
|
||||||
|
case VALUE_TYPE_STRING:
|
||||||
|
return (*value.value._string != '\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == NODE_TYPE_LIST ||
|
||||||
|
type == NODE_TYPE_ARRAY) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the node value is falsey
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool AstNode::isFalse () const {
|
||||||
|
return ! isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief whether or not a node is simple enough to be used in a simple
|
/// @brief whether or not a node is simple enough to be used in a simple
|
||||||
/// expression
|
/// expression
|
||||||
|
|
|
@ -51,12 +51,11 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
enum AstNodeValueType {
|
enum AstNodeValueType {
|
||||||
VALUE_TYPE_FAIL = 0,
|
VALUE_TYPE_NULL = 0,
|
||||||
VALUE_TYPE_NULL = 1,
|
VALUE_TYPE_BOOL = 1,
|
||||||
VALUE_TYPE_BOOL = 2,
|
VALUE_TYPE_INT = 2,
|
||||||
VALUE_TYPE_INT = 3,
|
VALUE_TYPE_DOUBLE = 3,
|
||||||
VALUE_TYPE_DOUBLE = 4,
|
VALUE_TYPE_STRING = 4
|
||||||
VALUE_TYPE_STRING = 5
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -154,7 +153,19 @@ namespace triagens {
|
||||||
/// @brief create the node
|
/// @brief create the node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AstNode (AstNodeType);
|
explicit AstNode (AstNodeType);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a node, with defining a value type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
explicit AstNode (AstNodeType, AstNodeValueType);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a boolean, with defining a value type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
explicit AstNode (bool);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief create the node from JSON
|
/// @brief create the node from JSON
|
||||||
|
@ -212,6 +223,8 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TRI_json_t* toJsonValue (TRI_memory_zone_t*) const;
|
TRI_json_t* toJsonValue (TRI_memory_zone_t*) const;
|
||||||
|
|
||||||
|
std::string toInfoString (TRI_memory_zone_t* zone) const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return a JSON representation of the node
|
/// @brief return a JSON representation of the node
|
||||||
|
@ -221,8 +234,6 @@ namespace triagens {
|
||||||
TRI_json_t* toJson (TRI_memory_zone_t*,
|
TRI_json_t* toJson (TRI_memory_zone_t*,
|
||||||
bool) const;
|
bool) const;
|
||||||
|
|
||||||
std::string toInfoString (TRI_memory_zone_t* zone) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief adds a JSON representation of the node to the JSON list specified
|
/// @brief adds a JSON representation of the node to the JSON list specified
|
||||||
/// in the first argument
|
/// in the first argument
|
||||||
|
@ -234,9 +245,55 @@ namespace triagens {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief convert the node's value to a boolean value
|
/// @brief convert the node's value to a boolean value
|
||||||
|
/// this may create a new node or return the node itself if it is already a
|
||||||
|
/// boolean value node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool toBoolean () const;
|
AstNode* castToBool (Ast*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief convert the node's value to a number value
|
||||||
|
/// this may create a new node or return the node itself if it is already a
|
||||||
|
/// numeric value node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode* castToNumber (Ast*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the node value is trueish
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool isTrue () const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the node value is falsey
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool isFalse () const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not a value node is NULL
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isNullValue () const {
|
||||||
|
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not a value node is an integer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isIntValue () const {
|
||||||
|
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not a value node is a dobule
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isDoubleValue () const {
|
||||||
|
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief whether or not a value node is of numeric type
|
/// @brief whether or not a value node is of numeric type
|
||||||
|
@ -401,28 +458,10 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return the int value of a node, without asserting the node type
|
/// @brief return the int value of a node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
inline int64_t getIntValue (bool) const {
|
int64_t getIntValue () const;
|
||||||
return value.value._int;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief return the int value of a node, with asserting the node type
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
inline int64_t getIntValue () const {
|
|
||||||
TRI_ASSERT(type == NODE_TYPE_VALUE);
|
|
||||||
TRI_ASSERT(value.type == VALUE_TYPE_INT ||
|
|
||||||
value.type == VALUE_TYPE_DOUBLE);
|
|
||||||
|
|
||||||
if (value.type == VALUE_TYPE_DOUBLE) {
|
|
||||||
return static_cast<int64_t>(value.value._double);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.value._int;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief set the int value of a node
|
/// @brief set the int value of a node
|
||||||
|
@ -436,17 +475,7 @@ namespace triagens {
|
||||||
/// @brief return the double value of a node
|
/// @brief return the double value of a node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
inline double getDoubleValue () const {
|
double getDoubleValue () const;
|
||||||
TRI_ASSERT(type == NODE_TYPE_VALUE);
|
|
||||||
TRI_ASSERT(value.type == VALUE_TYPE_INT ||
|
|
||||||
value.type == VALUE_TYPE_DOUBLE);
|
|
||||||
|
|
||||||
if (value.type == VALUE_TYPE_INT) {
|
|
||||||
return static_cast<double>(value.value._int);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.value._double;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief set the string value of a node
|
/// @brief set the string value of a node
|
||||||
|
|
|
@ -237,14 +237,14 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
|
||||||
TRI_ASSERT(value->isConstant());
|
TRI_ASSERT(value->isConstant());
|
||||||
|
|
||||||
if (strcmp(name, "waitForSync") == 0) {
|
if (strcmp(name, "waitForSync") == 0) {
|
||||||
options.waitForSync = value->toBoolean();
|
options.waitForSync = value->isTrue();
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "ignoreErrors") == 0) {
|
else if (strcmp(name, "ignoreErrors") == 0) {
|
||||||
options.ignoreErrors = value->toBoolean();
|
options.ignoreErrors = value->isTrue();
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "keepNull") == 0) {
|
else if (strcmp(name, "keepNull") == 0) {
|
||||||
// nullMeansRemove is the opposite of keepNull
|
// nullMeansRemove is the opposite of keepNull
|
||||||
options.nullMeansRemove = (! value->toBoolean());
|
options.nullMeansRemove = value->isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,7 +217,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
||||||
// we can now evaluate it safely
|
// we can now evaluate it safely
|
||||||
TRI_ASSERT(! s->expression()->canThrow());
|
TRI_ASSERT(! s->expression()->canThrow());
|
||||||
|
|
||||||
if (root->toBoolean()) {
|
if (root->isTrue()) {
|
||||||
// filter is always true
|
// filter is always true
|
||||||
// remove filter node and merge with following node
|
// remove filter node and merge with following node
|
||||||
toUnlink.insert(n);
|
toUnlink.insert(n);
|
||||||
|
|
|
@ -445,9 +445,9 @@ function executeAndWait (cmd, args) {
|
||||||
if (typeof(res.errorMessage) !== 'undefined') {
|
if (typeof(res.errorMessage) !== 'undefined') {
|
||||||
errorMessage += res.errorMessage;
|
errorMessage += res.errorMessage;
|
||||||
}
|
}
|
||||||
print("Finished: " + res.status + " Exitcode: " + res.exit + " Time Elapsed: " + deltaTime + errorMessage);
|
print("Finished: " + res.status + " Exitcode: " + res.signal + " Time Elapsed: " + deltaTime + errorMessage);
|
||||||
return {
|
return {
|
||||||
status: false,
|
status: res.status === 'RUNNING',
|
||||||
message: "irregular termination: " + res.status + " Exit-Code: " + res.exit + errorMessage,
|
message: "irregular termination: " + res.status + " Exit-Code: " + res.exit + errorMessage,
|
||||||
duration: deltaTime
|
duration: deltaTime
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
var errors = require("internal").errors;
|
var errors = require("internal").errors;
|
||||||
var jsunity = require("jsunity");
|
var jsunity = require("jsunity");
|
||||||
var helper = require("org/arangodb/aql-helper");
|
var helper = require("org/arangodb/aql-helper");
|
||||||
var getQueryResults = helper.getQueryResults2;
|
var getQueryResults = helper.getQueryResultsAQL2;
|
||||||
var assertQueryError = helper.assertQueryError2;
|
var assertQueryError = helper.assertQueryError2;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -107,13 +107,18 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test unary plus
|
/// @brief test unary plus
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testUnaryPlusInvalid : function () {
|
testUnaryPlusNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +null");
|
assertEqual([ 0 ], getQueryResults("RETURN +null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +true");
|
assertEqual([ 1 ], getQueryResults("RETURN +true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +false");
|
assertEqual([ 0 ], getQueryResults("RETURN +false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +\"value\"");
|
assertEqual([ null ], getQueryResults("RETURN +\"value\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +[ ]");
|
assertEqual([ 1 ], getQueryResults("RETURN +\"1\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN +{ }");
|
assertEqual([ -3 ], getQueryResults("RETURN +\"-3\""));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN +[ ]"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN +[ 0 ]"));
|
||||||
|
assertEqual([ -34 ], getQueryResults("RETURN +[ -34 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN +[ 1, 2 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN +{ }"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -170,13 +175,18 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test unary minus
|
/// @brief test unary minus
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testUnaryMinusInvalid : function () {
|
testUnaryMinusNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -null");
|
assertEqual([ 0 ], getQueryResults("RETURN -null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -true");
|
assertEqual([ -1 ], getQueryResults("RETURN -true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -false");
|
assertEqual([ 0 ], getQueryResults("RETURN -false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -\"value\"");
|
assertEqual([ null ], getQueryResults("RETURN -\"value\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -[ ]");
|
assertEqual([ -1 ], getQueryResults("RETURN -\"1\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN -{ }");
|
assertEqual([ 3 ], getQueryResults("RETURN -\"-3\""));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN -[ ]"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN -[ 0 ]"));
|
||||||
|
assertEqual([ 34 ], getQueryResults("RETURN -[ -34 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN -[ 1, 2 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN -{ }"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -254,19 +264,29 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test binary plus
|
/// @brief test binary plus
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testBinaryPlusInvalid : function () {
|
testBinaryPlusNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + null");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + false");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + \"0\"");
|
assertEqual([ 2 ], getQueryResults("RETURN 1 + true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ ]");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + \"0\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + [ 0 ]");
|
assertEqual([ 43 ], getQueryResults("RETURN 1 + \"42\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 + { }");
|
assertEqual([ -16 ], getQueryResults("RETURN 1 + \"-17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null + 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false + 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ 0 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" + 1");
|
assertEqual([ 5 ], getQueryResults("RETURN 1 + [ 4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] + 1");
|
assertEqual([ -3 ], getQueryResults("RETURN 1 + [ -4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] + 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 + { }"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } + 1");
|
assertEqual([ 1 ], getQueryResults("RETURN null + 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN false + 1"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN true + 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN \"0\" + 1"));
|
||||||
|
assertEqual([ 24 ], getQueryResults("RETURN \"23\" + 1"));
|
||||||
|
assertEqual([ -8 ], getQueryResults("RETURN \"-9\" + 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN [ ] + 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN [ 0 ] + 1"));
|
||||||
|
assertEqual([ 5 ], getQueryResults("RETURN [ 4 ] + 1"));
|
||||||
|
assertEqual([ -3 ], getQueryResults("RETURN [ -4 ] + 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN { } + 1"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -303,19 +323,30 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test binary minus
|
/// @brief test binary minus
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testBinaryMinusInvalid : function () {
|
testBinaryMinusNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - null");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - false");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - \"0\"");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 - true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ ]");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - \"0\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - [ 0 ]");
|
assertEqual([ -41 ], getQueryResults("RETURN 1 - \"42\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 - { }");
|
assertEqual([ 18 ], getQueryResults("RETURN 1 - \"-17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null - 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - [ ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false - 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - [ 0 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" - 1");
|
assertEqual([ -3 ], getQueryResults("RETURN 1 - [ 4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] - 1");
|
assertEqual([ 5 ], getQueryResults("RETURN 1 - [ -4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] - 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 - { }"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } - 1");
|
assertEqual([ -1 ], getQueryResults("RETURN null - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN false - 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN true - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN \"0\" - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN \"0\" - \"1\""));
|
||||||
|
assertEqual([ 22 ], getQueryResults("RETURN \"23\" - 1"));
|
||||||
|
assertEqual([ -10 ], getQueryResults("RETURN \"-9\" - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN [ ] - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN [ 0 ] - 1"));
|
||||||
|
assertEqual([ 3 ], getQueryResults("RETURN [ 4 ] - 1"));
|
||||||
|
assertEqual([ -5 ], getQueryResults("RETURN [ -4 ] - 1"));
|
||||||
|
assertEqual([ -1 ], getQueryResults("RETURN { } - 1"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -392,19 +423,31 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test binary multiplication
|
/// @brief test binary multiplication
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testBinaryMultiplicationInvalid : function () {
|
testBinaryMultiplicationNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * null");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * false");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * \"0\"");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 * true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ ]");
|
assertEqual([ 37 ], getQueryResults("RETURN 37 * true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * [ 0 ]");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * \"0\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 * { }");
|
assertEqual([ 42 ], getQueryResults("RETURN 1 * \"42\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null * 1");
|
assertEqual([ -17 ], getQueryResults("RETURN 1 * \"-17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false * 1");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * [ ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" * 1");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * [ 0 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] * 1");
|
assertEqual([ 4 ], getQueryResults("RETURN 1 * [ 4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] * 1");
|
assertEqual([ -4 ], getQueryResults("RETURN 1 * [ -4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } * 1");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 * { }"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN null * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN false * 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN true * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" * \"1\""));
|
||||||
|
assertEqual([ 23 ], getQueryResults("RETURN \"23\" * 1"));
|
||||||
|
assertEqual([ -9 ], getQueryResults("RETURN \"-9\" * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ ] * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] * 1"));
|
||||||
|
assertEqual([ 4 ], getQueryResults("RETURN [ 4 ] * 1"));
|
||||||
|
assertEqual([ -4 ], getQueryResults("RETURN [ -4 ] * 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN { } * 1"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -491,22 +534,35 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
/// @brief test binary division
|
/// @brief test binary division
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testBinaryDivisionInvalid : function () {
|
testBinaryDivisionNonNumeric : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / null");
|
assertEqual([ null ], getQueryResults("RETURN 1 / (1 - 1)"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / false");
|
assertEqual([ null ], getQueryResults("RETURN 1 / 0"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / \"0\"");
|
assertEqual([ null ], getQueryResults("RETURN 1 / 0.0"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ ]");
|
assertEqual([ null ], getQueryResults("RETURN 1 / (1 / 0)"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / [ 0 ]");
|
assertEqual([ null ], getQueryResults("RETURN 1 / null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 / { }");
|
assertEqual([ null ], getQueryResults("RETURN 1 / false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null / 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 / true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false / 1");
|
assertEqual([ 37 ], getQueryResults("RETURN 37 / true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" / 1");
|
assertEqual([ null ], getQueryResults("RETURN 1 / \"0\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] / 1");
|
assertEqual([ 0.25 ], getQueryResults("RETURN 1 / \"4\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] / 1");
|
assertEqual([ -2 ], getQueryResults("RETURN 34 / \"-17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } / 1");
|
assertEqual([ null ], getQueryResults("RETURN 1 / [ ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0");
|
assertEqual([ null ], getQueryResults("RETURN 1 / [ 0 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / 0.0");
|
assertEqual([ 0.25 ], getQueryResults("RETURN 1 / [ 4 ]"));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 / (1 - 1)");
|
assertEqual([ -0.25 ], getQueryResults("RETURN 1 / [ -4 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN 1 / { }"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN null / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN false / 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN true / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" / \"1\""));
|
||||||
|
assertEqual([ 23 ], getQueryResults("RETURN \"23\" / 1"));
|
||||||
|
assertEqual([ -9 ], getQueryResults("RETURN \"-9\" / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ ] / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] / 1"));
|
||||||
|
assertEqual([ 4 ], getQueryResults("RETURN [ 4 ] / 1"));
|
||||||
|
assertEqual([ -4 ], getQueryResults("RETURN [ -4 ] / 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN { } / 1"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -514,21 +570,45 @@ function ahuacatlArithmeticTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testBinaryModulusInvalid : function () {
|
testBinaryModulusInvalid : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % null");
|
assertEqual([ null ], getQueryResults("RETURN 1 % (1 - 1)"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % false");
|
assertEqual([ null ], getQueryResults("RETURN 1 % 0"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % \"0\"");
|
assertEqual([ null ], getQueryResults("RETURN 1 % 0.0"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ ]");
|
assertEqual([ null ], getQueryResults("RETURN 1 % (1 / 0)"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % [ 0 ]");
|
assertEqual([ null ], getQueryResults("RETURN 1 % null"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN 1 % { }");
|
assertEqual([ null ], getQueryResults("RETURN 1 % false"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN null % 1");
|
assertEqual([ 0 ], getQueryResults("RETURN 1 % true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN false % 1");
|
assertEqual([ 0 ], getQueryResults("RETURN 37 % true"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN \"0\" % 1");
|
assertEqual([ null ], getQueryResults("RETURN 1 % \"0\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ ] % 1");
|
assertEqual([ 1 ], getQueryResults("RETURN 1 % \"4\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN [ 0 ] % 1");
|
assertEqual([ 3 ], getQueryResults("RETURN 7 % \"4\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE.code, "RETURN { } % 1");
|
assertEqual([ 3 ], getQueryResults("RETURN 7 % \"-4\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0");
|
assertEqual([ 0 ], getQueryResults("RETURN 34 % \"-17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % 0.0");
|
assertEqual([ 1 ], getQueryResults("RETURN 35 % \"17\""));
|
||||||
assertQueryError(errors.ERROR_QUERY_DIVISION_BY_ZERO.code, "RETURN 1 % (1 - 1)");
|
assertEqual([ 1 ], getQueryResults("RETURN 35 % \"-17\""));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN 1 % [ ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN 1 % [ 0 ]"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN 13 % [ 4 ]"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN 1 % [ -4 ]"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN 13 % [ -4 ]"));
|
||||||
|
assertEqual([ null ], getQueryResults("RETURN 1 % { }"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN null % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN false % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN true % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"0\" % \"1\""));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"23\" % 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN \"23\" % 2"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN \"23\" % 3"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN \"23\" % 7"));
|
||||||
|
assertEqual([ 11 ], getQueryResults("RETURN \"23\" % 12"));
|
||||||
|
assertEqual([ 11 ], getQueryResults("RETURN \"23\" % \"12\""));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN \"-9\" % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ ] % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ 0 ] % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ 4 ] % 1"));
|
||||||
|
assertEqual([ 1 ], getQueryResults("RETURN [ 4 ] % 3"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN [ -4 ] % 1"));
|
||||||
|
assertEqual([ 0 ], getQueryResults("RETURN { } % 1"));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -411,16 +411,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidIn : function () {
|
testInvalidIn : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN null RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN null RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN false RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN false RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN 1.2 RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN 1.2 RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN '' RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN '' RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN {} RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN {} RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: null });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: null }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: false });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: false }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: 1.2 });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: 1.2 }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: "" });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: "" }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: { } });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 IN @values RETURN i", { values: { } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -428,16 +428,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidNotIn : function () {
|
testInvalidNotIn : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN null RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN null RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN false RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN false RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN 1.2 RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN 1.2 RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN '' RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN '' RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN {} RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN {} RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: null });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: null }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: false });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: false }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: 1.2 });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: 1.2 }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: "" });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: "" }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: { } });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN [ 1, 2, 3 ] FILTER 1 NOT IN @values RETURN i", { values: { } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -445,16 +445,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidInCollection : function () {
|
testInvalidInCollection : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN null RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN null RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN false RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN false RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN 1.2 RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN 1.2 RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN '' RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN '' RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN {} RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN {} RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: null });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: null }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: false });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: false }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: 1.2 });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: 1.2 }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: "" });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: "" }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: { } });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 IN @values RETURN i", { values: { } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -462,16 +462,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidNotInCollection : function () {
|
testInvalidNotInCollection : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN null RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN null RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN false RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN false RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN 1.2 RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN 1.2 RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN '' RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN '' RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN {} RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN {} RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: null });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: null }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: false });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: false }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: 1.2 });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: 1.2 }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: "" });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: "" }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: { } });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER 1 NOT IN @values RETURN i", { values: { } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -479,16 +479,16 @@ function ahuacatlQueryOptimiserInTestSuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidInCollectionIndex : function () {
|
testInvalidInCollectionIndex : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN null RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN null RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN false RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN false RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN 1.2 RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN 1.2 RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN '' RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN '' RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN {} RETURN i");
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN {} RETURN i"));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: null });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: null }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: false });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: false }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: 1.2 });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: 1.2 }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: "" });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: "" }));
|
||||||
assertQueryError(errors.ERROR_QUERY_LIST_EXPECTED.code, "FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: { } });
|
assertEqual([ ], getQueryResultsAQL2("FOR i IN " + cn + " FILTER i._id IN @values RETURN i", { values: { } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
var errors = require("internal").errors;
|
var errors = require("internal").errors;
|
||||||
var jsunity = require("jsunity");
|
var jsunity = require("jsunity");
|
||||||
var helper = require("org/arangodb/aql-helper");
|
var helper = require("org/arangodb/aql-helper");
|
||||||
var getQueryResults = helper.getQueryResults2;
|
var getQueryResults = helper.getQueryResultsAQL2;
|
||||||
var assertQueryError = helper.assertQueryError2;
|
var assertQueryError = helper.assertQueryError2;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -167,14 +167,19 @@ function ahuacatlTernaryTestSuite () {
|
||||||
/// @brief test ternary with non-boolean condition
|
/// @brief test ternary with non-boolean condition
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testTernaryInvalid : function () {
|
testTernaryNonBoolean : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN 1 ? 2 : 3");
|
assertEqual([ 2 ], getQueryResults("RETURN 1 ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN null ? 2 : 3");
|
assertEqual([ 3 ], getQueryResults("RETURN 0 ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4) ? 2 : 3");
|
assertEqual([ 3 ], getQueryResults("RETURN null ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN (4 - 3) ? 2 : 3");
|
assertEqual([ 3 ], getQueryResults("RETURN false ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN \"true\" ? 2 : 3");
|
assertEqual([ 2 ], getQueryResults("RETURN true ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN [ ] ? 2 : 3");
|
assertEqual([ 2 ], getQueryResults("RETURN (4) ? 2 : 3"));
|
||||||
assertQueryError(errors.ERROR_QUERY_INVALID_LOGICAL_VALUE.code, "RETURN { } ? 2 : 3");
|
assertEqual([ 2 ], getQueryResults("RETURN (4 - 3) ? 2 : 3"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN \"true\" ? 2 : 3"));
|
||||||
|
assertEqual([ 3 ], getQueryResults("RETURN \"\" ? 2 : 3"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN [ ] ? 2 : 3"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN [ 0 ] ? 2 : 3"));
|
||||||
|
assertEqual([ 2 ], getQueryResults("RETURN { } ? 2 : 3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/*jshint strict: false */
|
||||||
|
/*global require, assertTrue, assertEqual, assertMatch, fail */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test the task manager
|
/// @brief test the task manager
|
||||||
///
|
///
|
||||||
|
@ -421,7 +424,7 @@ function TaskSuite () {
|
||||||
assertEqual(10, task.offset);
|
assertEqual(10, task.offset);
|
||||||
assertEqual("_system", task.database);
|
assertEqual("_system", task.database);
|
||||||
|
|
||||||
t = getTasks();
|
var t = getTasks();
|
||||||
assertEqual(1, t.length);
|
assertEqual(1, t.length);
|
||||||
|
|
||||||
internal.wait(2);
|
internal.wait(2);
|
||||||
|
@ -456,7 +459,7 @@ function TaskSuite () {
|
||||||
assertEqual(2, task.offset);
|
assertEqual(2, task.offset);
|
||||||
assertEqual("_system", task.database);
|
assertEqual("_system", task.database);
|
||||||
|
|
||||||
t = getTasks();
|
var t = getTasks();
|
||||||
assertEqual(1, t.length);
|
assertEqual(1, t.length);
|
||||||
|
|
||||||
internal.wait(5);
|
internal.wait(5);
|
||||||
|
@ -492,7 +495,7 @@ function TaskSuite () {
|
||||||
|
|
||||||
internal.wait(1);
|
internal.wait(1);
|
||||||
|
|
||||||
t = getTasks();
|
var t = getTasks();
|
||||||
assertEqual(0, t.length);
|
assertEqual(0, t.length);
|
||||||
|
|
||||||
internal.wait(5);
|
internal.wait(5);
|
||||||
|
@ -526,7 +529,7 @@ function TaskSuite () {
|
||||||
assertEqual(5, task.offset);
|
assertEqual(5, task.offset);
|
||||||
assertEqual("_system", task.database);
|
assertEqual("_system", task.database);
|
||||||
|
|
||||||
t = getTasks();
|
var t = getTasks();
|
||||||
assertEqual(1, t.length);
|
assertEqual(1, t.length);
|
||||||
|
|
||||||
internal.wait(15);
|
internal.wait(15);
|
||||||
|
@ -572,7 +575,7 @@ function TaskSuite () {
|
||||||
assertEqual(0, db[cn].count());
|
assertEqual(0, db[cn].count());
|
||||||
assertEqual(0, db[cn].byExample({ value: 23 }).toArray().length);
|
assertEqual(0, db[cn].byExample({ value: 23 }).toArray().length);
|
||||||
|
|
||||||
t = getTasks();
|
var t = getTasks();
|
||||||
assertEqual(0, t.length);
|
assertEqual(0, t.length);
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -220,15 +220,6 @@ static bool CreatePipes (int* pipe_server_to_child,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief handler for SIGCHLD
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void handleSigchld (int sig) {
|
|
||||||
// intentionally do nothing here
|
|
||||||
// we'll use waitpid() for reaping children later
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief starts external process
|
/// @brief starts external process
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1280,17 +1271,6 @@ void TRI_InitialiseProcess (int argc, char* argv[]) {
|
||||||
|
|
||||||
TRI_InitVectorPointer(&ExternalProcesses, TRI_CORE_MEM_ZONE);
|
TRI_InitVectorPointer(&ExternalProcesses, TRI_CORE_MEM_ZONE);
|
||||||
TRI_InitMutex(&ExternalProcessesLock);
|
TRI_InitMutex(&ExternalProcessesLock);
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
// initialise a signal handler for SIGCHLD
|
|
||||||
struct sigaction sa;
|
|
||||||
sa.sa_handler = &handleSigchld;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
|
||||||
if (sigaction(SIGCHLD, &sa, 0) == -1) {
|
|
||||||
// installation of signal handler failed
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue