diff --git a/arangod/Aql/AqlValue.cpp b/arangod/Aql/AqlValue.cpp index 6d8760ede1..80d05eb2a5 100644 --- a/arangod/Aql/AqlValue.cpp +++ b/arangod/Aql/AqlValue.cpp @@ -155,6 +155,35 @@ bool AqlValue::isArray() const noexcept { } } +std::array AqlValue::typeStrings = { + "none", + "null", + "bool", + "number", + "string", + "object", + "array", + "unknown"}; + +std::string const & AqlValue::getTypeString() const noexcept { + if(isNone()) { + return typeStrings[0]; + } else if(isNull(true)) { + return typeStrings[1]; + } else if(isBoolean()) { + return typeStrings[2]; + } else if(isNumber()) { + return typeStrings[3]; + } else if(isString()) { + return typeStrings[4]; + } else if(isObject()) { + return typeStrings[5]; + } else if(isArray()){ + return typeStrings[6]; + } + return typeStrings[7]; +} + /// @brief get the (array) length (note: this treats ranges as arrays, too!) size_t AqlValue::length() const { switch (type()) { diff --git a/arangod/Aql/AqlValue.h b/arangod/Aql/AqlValue.h index 94546a24f3..3fdfe71c4a 100644 --- a/arangod/Aql/AqlValue.h +++ b/arangod/Aql/AqlValue.h @@ -83,6 +83,7 @@ struct AqlValueFromManagedDocument {}; struct AqlValue final { friend struct std::hash; friend struct std::equal_to; + static std::array typeStrings; public: @@ -388,6 +389,10 @@ struct AqlValue final { /// @brief whether or not the value is an array (note: this treats ranges /// as arrays, too!) bool isArray() const noexcept; + + // @brief return a string describing the content of this aqlvalue + std::string const & getTypeString() const noexcept; + /// @brief get the (array) length (note: this treats ranges as arrays, too!) size_t length() const; diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 2dc445388c..d1fd12c2df 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -2889,8 +2889,13 @@ AstNode* Ast::optimizeFor(AstNode* node) { // right-hand operand to FOR statement is no array THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_QUERY_ARRAY_EXPECTED, + std::string("collection or ") + TRI_errno_string(TRI_ERROR_QUERY_ARRAY_EXPECTED) + - std::string(" as operand to FOR loop")); + std::string(" as operand to FOR loop; you specified type '") + + expression->getValueTypeString() + + std::string("' with content '") + + expression->toString() + + std::string("'")); } // no real optimizations will be done here diff --git a/arangod/Aql/EnumerateListBlock.cpp b/arangod/Aql/EnumerateListBlock.cpp index fc73d107b9..0b2565dcc9 100644 --- a/arangod/Aql/EnumerateListBlock.cpp +++ b/arangod/Aql/EnumerateListBlock.cpp @@ -98,7 +98,7 @@ AqlItemBlock* EnumerateListBlock::getSome(size_t, size_t atMost) { AqlValue const& inVarReg = cur->getValueReference(_pos, _inVarRegId); if (!inVarReg.isArray()) { - throwArrayExpectedException(); + throwArrayExpectedException(inVarReg); } size_t sizeInVar; @@ -195,7 +195,7 @@ size_t EnumerateListBlock::skipSome(size_t atLeast, size_t atMost) { AqlValue const& inVarReg = cur->getValueReference(_pos, _inVarRegId); // get the size of the thing we are looping over if (!inVarReg.isArray()) { - throwArrayExpectedException(); + throwArrayExpectedException(inVarReg); } size_t sizeInVar; @@ -253,9 +253,12 @@ AqlValue EnumerateListBlock::getAqlValue(AqlValue const& inVarReg, bool& mustDes DEBUG_END_BLOCK(); } -void EnumerateListBlock::throwArrayExpectedException() { +void EnumerateListBlock::throwArrayExpectedException(AqlValue const& value) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_QUERY_ARRAY_EXPECTED, + std::string("collection or ") + TRI_errno_string(TRI_ERROR_QUERY_ARRAY_EXPECTED) + - std::string(" as operand to FOR loop")); + std::string(" as operand to FOR loop; you provided a value of type '") + + value.getTypeString () + + std::string("'")); } diff --git a/arangod/Aql/EnumerateListBlock.h b/arangod/Aql/EnumerateListBlock.h index 83b691a0d1..c58f6c5c81 100644 --- a/arangod/Aql/EnumerateListBlock.h +++ b/arangod/Aql/EnumerateListBlock.h @@ -54,7 +54,7 @@ class EnumerateListBlock : public ExecutionBlock { AqlValue getAqlValue(AqlValue const&, bool& mustDestroy); // cppcheck-suppress * - void throwArrayExpectedException(); + void throwArrayExpectedException(AqlValue const& value); private: // current position in the _inVariable diff --git a/arangod/Scheduler/SocketTask.cpp b/arangod/Scheduler/SocketTask.cpp index ad6dce3bd7..fbde164074 100644 --- a/arangod/Scheduler/SocketTask.cpp +++ b/arangod/Scheduler/SocketTask.cpp @@ -80,7 +80,7 @@ SocketTask::~SocketTask() { if (err) { LOG_TOPIC(ERR, Logger::COMMUNICATION) << "unable to cancel _keepAliveTimer"; - } + } } void SocketTask::start() { @@ -163,28 +163,26 @@ void SocketTask::addWriteBuffer(StringBuffer* buffer, size_t written = 0; boost::system::error_code err; - do { - err.assign(boost::system::errc::success, - boost::system::generic_category()); - written = _peer->write(_writeBuffer, err); - if(_writeBufferStatistics){ - _writeBufferStatistics->_sentBytes += written; - } - if (written == total) { - locker.unlock(); - completedWriteBuffer(); - return; - } - } while (err == boost::asio::error::would_block); + written = _peer->write(_writeBuffer, err); - if (err != boost::system::errc::success) { + if(_writeBufferStatistics){ + _writeBufferStatistics->_sentBytes += written; + } + + if (written == total) { + locker.unlock(); + completedWriteBuffer(); + return; + } + + if (err != boost::system::errc::success && err!= boost::asio::error::would_block) { LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "SocketTask::addWriteBuffer (write_some) - write on stream " << " failed with: " << err.message(); closeStream(); return; } - + boost::system::error_code ec; ec.assign(boost::system::errc::success, boost::system::generic_category());