diff --git a/CHANGELOG b/CHANGELOG index 44a3bd4195..97b460cd18 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,10 +42,14 @@ devel v3.0.5 (XXXX-XX-XX) ------------------- +* execute AQL ternary operator via C++ if possible + * fixed issue #1977 * fixed extraction of _id attribute in AQL traversal conditions +* fix SSL agency endpoint + v3.0.4 (2016-08-01) ------------------- diff --git a/README.md b/README.md index 18cb99bc2d..3b7163559a 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ ArangoDB 2.8: [![Build Status](https://secure.travis-ci.org/arangodb/arangodb.png?branch=2.8)](http://travis-ci.org/arangodb/arangodb) 3.0: [![Build Status](https://secure.travis-ci.org/arangodb/arangodb.png?branch=3.0)](http://travis-ci.org/arangodb/arangodb) -Master: [![Build Status](https://secure.travis-ci.org/arangodb/arangodb.png?branch=master)](http://travis-ci.org/arangodb/arangodb) - Slack: [![ArangoDB-Logo](http://slack.arangodb.com/badge.svg)](https://slack.arangodb.com) ArangoDB is a multi-model, open-source database with flexible data models for diff --git a/arangod/Aql/AqlValue.cpp b/arangod/Aql/AqlValue.cpp index 92fd03cf2d..ffaf8d70e8 100644 --- a/arangod/Aql/AqlValue.cpp +++ b/arangod/Aql/AqlValue.cpp @@ -210,11 +210,7 @@ AqlValue AqlValue::at(arangodb::AqlTransaction* trx, int64_t position, if (position >= 0 && position < static_cast(n)) { // only look up the value if it is within array bounds - TransactionBuilderLeaser builder(trx); - builder->add( - VPackValue(_data.range->at(static_cast(position)))); - mustDestroy = true; - return AqlValue(builder->slice()); + return AqlValue(_data.range->at(static_cast(position))); } // fall-through intentional break; diff --git a/arangod/Aql/AqlValue.h b/arangod/Aql/AqlValue.h index f0cbbc484c..b4a5082590 100644 --- a/arangod/Aql/AqlValue.h +++ b/arangod/Aql/AqlValue.h @@ -38,6 +38,39 @@ #include +// some functionality borrowed from 3rdParty/velocypack/include/velocypack +// this is a copy of that functionality, because the functions in velocypack +// are not accessible from here +namespace { + static inline uint64_t toUInt64(int64_t v) noexcept { + // If v is negative, we need to add 2^63 to make it positive, + // before we can cast it to an uint64_t: + uint64_t shift2 = 1ULL << 63; + int64_t shift = static_cast(shift2 - 1); + return v >= 0 ? static_cast(v) + : static_cast((v + shift) + 1) + shift2; + // Note that g++ and clang++ with -O3 compile this away to + // nothing. Further note that a plain cast from int64_t to + // uint64_t is not guaranteed to work for negative values! + } + + // returns number of bytes required to store the value in 2s-complement + static inline uint8_t intLength(int64_t value) { + if (value >= -0x80 && value <= 0x7f) { + // shortcut for the common case + return 1; + } + uint64_t x = value >= 0 ? static_cast(value) + : static_cast(-(value + 1)); + uint8_t xSize = 0; + do { + xSize++; + x >>= 8; + } while (x >= 0x80); + return xSize + 1; + } +} + struct TRI_doc_mptr_t; namespace arangodb { @@ -132,6 +165,75 @@ struct AqlValue final { memcpy(_data.internal, slice.begin(), static_cast(slice.byteSize())); setType(AqlValueType::VPACK_INLINE); } + + // construct from a double value + explicit AqlValue(double value) { + if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) { + // null + _data.internal[0] = 0x18; + } else { + // a "real" double + _data.internal[0] = 0x1b; + uint64_t dv; + memcpy(&dv, &value, sizeof(double)); + VPackValueLength vSize = sizeof(double); + int i = 1; + for (uint64_t x = dv; vSize > 0; vSize--) { + _data.internal[i] = x & 0xff; + x >>= 8; + ++i; + } + } + setType(AqlValueType::VPACK_INLINE); + } + + // construct from an int64 value + explicit AqlValue(int64_t value) { + if (value >= 0 && value <= 9) { + // a smallint + _data.internal[0] = static_cast(0x30U + value); + } else if (value < 0 && value >= -6) { + // a negative smallint + _data.internal[0] = static_cast(0x40U + value); + } else { + uint8_t vSize = intLength(value); + uint64_t x; + if (vSize == 8) { + x = toUInt64(value); + } else { + int64_t shift = 1LL << (vSize * 8 - 1); // will never overflow! + x = value >= 0 ? static_cast(value) + : static_cast(value + shift) + shift; + } + _data.internal[0] = 0x1fU + vSize; + int i = 1; + while (vSize-- > 0) { + _data.internal[i] = x & 0xffU; + ++i; + x >>= 8; + } + } + setType(AqlValueType::VPACK_INLINE); + } + + // construct from a uint64 value + explicit AqlValue(uint64_t value) { + if (value <= 9) { + // a smallint + _data.internal[0] = static_cast(0x30U + value); + } else { + int i = 1; + uint8_t vSize = 0; + do { + vSize++; + _data.internal[i] = static_cast(value & 0xffU); + ++i; + value >>= 8; + } while (value != 0); + _data.internal[0] = 0x27U + vSize; + } + setType(AqlValueType::VPACK_INLINE); + } // construct from char* and length, copying the string AqlValue(char const* value, size_t length) { diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index ad37c395b9..e38d56d842 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -1719,7 +1719,8 @@ bool AstNode::isSimple() const { } if (type == NODE_TYPE_OBJECT_ELEMENT || type == NODE_TYPE_ATTRIBUTE_ACCESS || - type == NODE_TYPE_OPERATOR_UNARY_NOT) { + type == NODE_TYPE_OPERATOR_UNARY_NOT || type == NODE_TYPE_OPERATOR_UNARY_PLUS || + type == NODE_TYPE_OPERATOR_UNARY_MINUS) { TRI_ASSERT(numMembers() == 1); if (!getMember(0)->isSimple()) { diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index bd93cc4c64..7732928acc 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -444,6 +444,12 @@ AqlValue Expression::executeSimpleExpression( regs, mustDestroy); case NODE_TYPE_OPERATOR_UNARY_NOT: return executeSimpleExpressionNot(node, trx, argv, startPos, vars, regs, mustDestroy); + + case NODE_TYPE_OPERATOR_UNARY_PLUS: + return executeSimpleExpressionPlus(node, trx, argv, startPos, vars, regs, mustDestroy); + + case NODE_TYPE_OPERATOR_UNARY_MINUS: + return executeSimpleExpressionMinus(node, trx, argv, startPos, vars, regs, mustDestroy); case NODE_TYPE_OPERATOR_BINARY_AND: case NODE_TYPE_OPERATOR_BINARY_OR: @@ -558,9 +564,9 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess( // etc. TRI_ASSERT(node->numMembers() == 2); - auto member = node->getMember(0); - auto index = node->getMember(1); - + auto member = node->getMemberUnchecked(0); + auto index = node->getMemberUnchecked(1); + mustDestroy = false; AqlValue result = executeSimpleExpression(member, trx, argv, startPos, vars, regs, mustDestroy, false); @@ -815,7 +821,7 @@ AqlValue Expression::executeSimpleExpressionReference( auto v = static_cast(node->getData()); TRI_ASSERT(v != nullptr); - { + if (!_variables.empty()) { auto it = _variables.find(v); if (it != _variables.end()) { @@ -825,7 +831,7 @@ AqlValue Expression::executeSimpleExpressionReference( } size_t i = 0; - for (auto it = vars.begin(); it != vars.end(); ++it, ++i) { + for (auto it = vars.begin(), it2 = vars.end(); it != it2; ++it, ++i) { if ((*it)->id == v->id) { if (doCopy) { mustDestroy = true; // as we are copying @@ -947,6 +953,84 @@ AqlValue Expression::executeSimpleExpressionNot( return AqlValue(!operandIsTrue); } +/// @brief execute an expression of type SIMPLE with + +AqlValue Expression::executeSimpleExpressionPlus( + AstNode const* node, arangodb::AqlTransaction* trx, + AqlItemBlock const* argv, size_t startPos, + std::vector const& vars, + std::vector const& regs, bool& mustDestroy) { + + mustDestroy = false; + AqlValue operand = + executeSimpleExpression(node->getMember(0), trx, argv, + startPos, vars, regs, mustDestroy, false); + + AqlValueGuard guard(operand, mustDestroy); + + if (operand.isNumber()) { + VPackSlice const s = operand.slice(); + + if (s.isSmallInt() || s.isInt()) { + // can use int64 + return AqlValue(s.getNumber()); + } else if (s.isUInt()) { + // can use uint64 + return AqlValue(s.getNumber()); + } + // fallthrouh intentional + } + + // use a double value for all other cases + bool failed = false; + double value = operand.toDouble(trx, failed); + + if (failed) { + value = 0.0; + } + + return AqlValue(+value); +} + +/// @brief execute an expression of type SIMPLE with - +AqlValue Expression::executeSimpleExpressionMinus( + AstNode const* node, arangodb::AqlTransaction* trx, + AqlItemBlock const* argv, size_t startPos, + std::vector const& vars, + std::vector const& regs, bool& mustDestroy) { + + mustDestroy = false; + AqlValue operand = + executeSimpleExpression(node->getMember(0), trx, argv, + startPos, vars, regs, mustDestroy, false); + + AqlValueGuard guard(operand, mustDestroy); + + if (operand.isNumber()) { + VPackSlice const s = operand.slice(); + if (s.isSmallInt()) { + // can use int64 + return AqlValue(-s.getNumber()); + } else if (s.isInt()) { + int64_t v = s.getNumber(); + if (v != INT64_MIN) { + // can use int64 + return AqlValue(-v); + } + } + // fallthrouh intentional + } + + // TODO: handle integer values separately here + bool failed = false; + double value = operand.toDouble(trx, failed); + + if (failed) { + value = 0.0; + } + + return AqlValue(-value); +} + /// @brief execute an expression of type SIMPLE with AND or OR AqlValue Expression::executeSimpleExpressionAndOr( AstNode const* node, arangodb::AqlTransaction* trx, diff --git a/arangod/Aql/Expression.h b/arangod/Aql/Expression.h index 02a1a3f74d..25290dda7e 100644 --- a/arangod/Aql/Expression.h +++ b/arangod/Aql/Expression.h @@ -34,8 +34,6 @@ #include #include -struct TRI_json_t; - namespace arangodb { class AqlTransaction; @@ -293,6 +291,20 @@ class Expression { std::vector const&, std::vector const&, bool& mustDestroy); + + /// @brief execute an expression of type SIMPLE with + + AqlValue executeSimpleExpressionPlus(AstNode const*, arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&, + bool& mustDestroy); + + /// @brief execute an expression of type SIMPLE with - + AqlValue executeSimpleExpressionMinus(AstNode const*, arangodb::AqlTransaction*, + AqlItemBlock const*, size_t, + std::vector const&, + std::vector const&, + bool& mustDestroy); /// @brief execute an expression of type SIMPLE with AND or OR AqlValue executeSimpleExpressionAndOr(AstNode const*, diff --git a/arangod/VocBase/collection.cpp b/arangod/VocBase/collection.cpp index 024472dfe9..ba2a4b060f 100644 --- a/arangod/VocBase/collection.cpp +++ b/arangod/VocBase/collection.cpp @@ -599,7 +599,7 @@ void TRI_collection_t::addIndexFile(std::string const& filename) { //////////////////////////////////////////////////////////////////////////////// int TRI_collection_t::removeIndexFile(TRI_idx_iid_t id) { - READ_LOCKER(readLocker, _filesLock); + WRITE_LOCKER(readLocker, _filesLock); for (auto it = _indexFiles.begin(); it != _indexFiles.end(); ++it) { if (GetNumericFilenamePart((*it).c_str()) == id) { diff --git a/js/client/modules/@arangodb/testing.js b/js/client/modules/@arangodb/testing.js index 7e8de7cafa..b28e86eff0 100644 --- a/js/client/modules/@arangodb/testing.js +++ b/js/client/modules/@arangodb/testing.js @@ -897,8 +897,6 @@ function executeArangod (cmd, args, options) { testfn += '_'; } - testfn += valgrindTest; - if (valgrindOpts.xml === 'yes') { valgrindOpts['xml-file'] = testfn + '.%p.xml'; } @@ -1055,7 +1053,7 @@ function runInArangosh (options, instanceInfo, file, addArgs) { function createArangoshRunner(args) { let runner = function(options, instanceInfo, file) { return runInArangosh(options, instanceInfo, file, args); - } + }; runner.info = 'arangosh'; return runner; } @@ -1195,7 +1193,7 @@ function shutdownInstance (instanceInfo, options) { const n = instanceInfo.arangods.length; let nonagencies = instanceInfo.arangods - .filter(arangod => arangod.role != 'agent'); + .filter(arangod => arangod.role !== 'agent'); nonagencies.forEach(arangod => shutdownArangod(arangod, options) ); @@ -1219,7 +1217,7 @@ function shutdownInstance (instanceInfo, options) { // are agents: if (!agentsKilled && nrAgents > 0 && toShutdown.length === nrAgents) { instanceInfo.arangods - .filter(arangod => arangod.role == 'agent') + .filter(arangod => arangod.role === 'agent') .forEach(arangod => shutdownArangod(arangod, options)); agentsKilled = true; } diff --git a/js/client/tests/resilience/foxxmaster.js b/js/client/tests/resilience/foxxmaster.js index 01935e1b67..0b41640361 100644 --- a/js/client/tests/resilience/foxxmaster.js +++ b/js/client/tests/resilience/foxxmaster.js @@ -1,5 +1,5 @@ /*jshint strict: false, sub: true */ -/*global print, arango */ +/*global print, arango, assertTrue, assertNotNull, assertNotUndefined */ 'use strict'; //////////////////////////////////////////////////////////////////////////////// @@ -64,7 +64,7 @@ let executeOnServer = function(code) { } else { throw new Error('Could not send to server ' + JSON.stringify(reply)); } -} +}; function serverSetup() { let directory = require('./js/client/assets/queuetest/dirname.js'); @@ -112,23 +112,23 @@ function FoxxmasterSuite() { assertNotNull(server); let instance = instanceInfo.arangods.filter(arangod => { - if (arangod.role == 'agent') { + if (arangod.role === 'agent') { return false; } let url = arangod.endpoint.replace(/tcp/, 'http') + '/_admin/server/id'; let res = request({method: 'GET', url: url}); let parsed = JSON.parse(res.body); - if (parsed.id == server) { + if (parsed.id === server) { assertTrue(suspendExternal(arangod.pid)); } - return parsed.id == server; + return parsed.id === server; })[0]; assertNotUndefined(instance); assertTrue(suspendExternal(instance.pid)); let newEndpoint = instanceInfo.arangods.filter(arangod => { - return arangod.role == 'coordinator' && arangod.pid != instance.pid; + return arangod.role === 'coordinator' && arangod.pid !== instance.pid; })[0]; arango.reconnect(newEndpoint.endpoint, db._name(), 'root', ''); let waitInterval = 0.1; @@ -137,7 +137,7 @@ function FoxxmasterSuite() { while (waited <= 20) { document = db._collection('foxxqueuetest').document('test'); let newServer = document.server; - if (server != newServer) { + if (server !== newServer) { ok = true; break; } @@ -150,7 +150,7 @@ function FoxxmasterSuite() { throw new Error('Supervision should have moved the foxxqueues and foxxqueues should have been started to run on a new coordinator'); } } - } + }; } //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/aql/aql-arithmetic.js b/js/server/tests/aql/aql-arithmetic.js index a6da828505..897f4243d2 100644 --- a/js/server/tests/aql/aql-arithmetic.js +++ b/js/server/tests/aql/aql-arithmetic.js @@ -62,6 +62,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 0 ]; var actual = getQueryResults("RETURN +0"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(+0)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(+0)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -72,6 +76,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 1 ]; var actual = getQueryResults("RETURN +1"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(+1)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(+1)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -82,6 +90,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 1 ]; var actual = getQueryResults("RETURN ++1"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(++1)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(++1)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -92,6 +104,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ -5 ]; var actual = getQueryResults("RETURN +-5"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(+-5)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(+-5)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -102,6 +118,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 5.4 ]; var actual = getQueryResults("RETURN +++5.4"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(+++5.4)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(+++5.4)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -123,6 +143,36 @@ function ahuacatlArithmeticTestSuite () { assertEqual([ 0 ], getQueryResults("RETURN +[ \"abc\" ]")); assertEqual([ 3 ], getQueryResults("RETURN +[ \"3\" ]")); assertEqual([ 0 ], getQueryResults("RETURN +{ }")); + + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+null)")); + assertEqual([ 1 ], getQueryResults("RETURN NOOPT(+true)")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+false)")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+\"value\")")); + assertEqual([ 1 ], getQueryResults("RETURN NOOPT(+\"1\")")); + assertEqual([ -3 ], getQueryResults("RETURN NOOPT(+\"-3\")")); + assertEqual([ -3.4 ], getQueryResults("RETURN NOOPT(+\"-3.4\")")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+[ ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+[ 0 ])")); + assertEqual([ -34 ], getQueryResults("RETURN NOOPT(+[ -34 ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+[ 1, 2 ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+[ \"abc\" ])")); + assertEqual([ 3 ], getQueryResults("RETURN NOOPT(+[ \"3\" ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(+{ })")); + + assertEqual([ 0 ], getQueryResults("RETURN V8(+null)")); + assertEqual([ 1 ], getQueryResults("RETURN V8(+true)")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+false)")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+\"value\")")); + assertEqual([ 1 ], getQueryResults("RETURN V8(+\"1\")")); + assertEqual([ -3 ], getQueryResults("RETURN V8(+\"-3\")")); + assertEqual([ -3.4 ], getQueryResults("RETURN V8(+\"-3.4\")")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+[ ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+[ 0 ])")); + assertEqual([ -34 ], getQueryResults("RETURN V8(+[ -34 ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+[ 1, 2 ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+[ \"abc\" ])")); + assertEqual([ 3 ], getQueryResults("RETURN V8(+[ \"3\" ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(+{ })")); }, //////////////////////////////////////////////////////////////////////////////// @@ -133,6 +183,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 0 ]; var actual = getQueryResults("RETURN -0"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(-0)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(-0)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -143,6 +197,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ -1 ]; var actual = getQueryResults("RETURN -1"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(-1)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(-1)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -153,6 +211,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ 1 ]; var actual = getQueryResults("RETURN --1"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(--1)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(--1)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -163,6 +225,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ -5 ]; var actual = getQueryResults("RETURN -+5"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(-+5)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(-+5)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -173,6 +239,10 @@ function ahuacatlArithmeticTestSuite () { var expected = [ -5.4 ]; var actual = getQueryResults("RETURN ---5.4"); assertEqual(expected, actual); + actual = getQueryResults("RETURN NOOPT(---5.4)"); + assertEqual(expected, actual); + actual = getQueryResults("RETURN V8(---5.4)"); + assertEqual(expected, actual); }, //////////////////////////////////////////////////////////////////////////////// @@ -194,6 +264,36 @@ function ahuacatlArithmeticTestSuite () { assertEqual([ 0 ], getQueryResults("RETURN -[ \"abc\" ]")); assertEqual([ -3 ], getQueryResults("RETURN -[ \"3\" ]")); assertEqual([ 0 ], getQueryResults("RETURN -{ }")); + + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-null)")); + assertEqual([ -1 ], getQueryResults("RETURN NOOPT(-true)")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-false)")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-\"value\")")); + assertEqual([ -1 ], getQueryResults("RETURN NOOPT(-\"1\")")); + assertEqual([ 3 ], getQueryResults("RETURN NOOPT(-\"-3\")")); + assertEqual([ 3.5 ], getQueryResults("RETURN NOOPT(-\"-3.5\")")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-[ ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-[ 0 ])")); + assertEqual([ 34 ], getQueryResults("RETURN NOOPT(-[ -34 ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-[ 1, 2 ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-[ \"abc\" ])")); + assertEqual([ -3 ], getQueryResults("RETURN NOOPT(-[ \"3\" ])")); + assertEqual([ 0 ], getQueryResults("RETURN NOOPT(-{ })")); + + assertEqual([ 0 ], getQueryResults("RETURN V8(-null)")); + assertEqual([ -1 ], getQueryResults("RETURN V8(-true)")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-false)")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-\"value\")")); + assertEqual([ -1 ], getQueryResults("RETURN V8(-\"1\")")); + assertEqual([ 3 ], getQueryResults("RETURN V8(-\"-3\")")); + assertEqual([ 3.5 ], getQueryResults("RETURN V8(-\"-3.5\")")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-[ ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-[ 0 ])")); + assertEqual([ 34 ], getQueryResults("RETURN V8(-[ -34 ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-[ 1, 2 ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-[ \"abc\" ])")); + assertEqual([ -3 ], getQueryResults("RETURN V8(-[ \"3\" ])")); + assertEqual([ 0 ], getQueryResults("RETURN V8(-{ })")); }, ////////////////////////////////////////////////////////////////////////////////