diff --git a/CHANGELOG b/CHANGELOG index e497a89112..c05f59f45c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,12 @@ devel ----- +* make AQL return a proper error message in case of a unique key constraint + violation. previously it only returned the generic "unique constraint violated" + error message but omitted the details about which index caused the problem. + + This addresses https://stackoverflow.com/questions/46427126/arangodb-3-2-unique-constraint-violation-id-or-key + * fix potential overflow in CRC marker check when a corrupted CRC marker is found at the very beginning of an MMFiles datafile @@ -33,6 +39,13 @@ devel eight times as high as the previous recommended value. Increasing the values helps to prevent an ArangoDB server from running out of memory mappings. + The raised minimum recommended value may lead to ArangoDB showing some startup + warnings as follows: + + WARNING {memory} maximum number of memory mappings per process is 65530, which seems too low. it is recommended to set it to at least 512000 + WARNING {memory} execute 'sudo sysctl -w "vm.max_map_count=512000"' + + v3.2.4 (2017-XX-XX) ------------------- diff --git a/arangod/Aql/ModificationBlocks.cpp b/arangod/Aql/ModificationBlocks.cpp index db8a42e98c..0442f8aee9 100644 --- a/arangod/Aql/ModificationBlocks.cpp +++ b/arangod/Aql/ModificationBlocks.cpp @@ -327,7 +327,7 @@ AqlItemBlock* RemoveBlock::work(std::vector& blocks) { keyBuilder.close(); } else { // We have an error, handle it - handleResult(errorCode, ep->_options.ignoreErrors); + handleResult(errorCode, ep->_options.ignoreErrors, nullptr); } } } @@ -370,7 +370,7 @@ AqlItemBlock* RemoveBlock::work(std::vector& blocks) { if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) { result->emplaceValue(dstRow, _outRegOld, it.get("old")); } - handleResult(errorCode, ep->_options.ignoreErrors); + handleResult(errorCode, ep->_options.ignoreErrors, nullptr); ++iter; } ++dstRow; @@ -392,7 +392,7 @@ AqlItemBlock* RemoveBlock::work(std::vector& blocks) { if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) { result->emplaceValue(dstRow, _outRegOld, opRes.slice().get("old")); } - handleResult(errorCode, ep->_options.ignoreErrors); + handleResult(errorCode, ep->_options.ignoreErrors, nullptr); ++dstRow; } } else { @@ -426,6 +426,7 @@ AqlItemBlock* InsertBlock::work(std::vector& blocks) { TRI_ASSERT(it != ep->getRegisterPlan()->varInfo.end()); RegisterId const registerId = it->second.registerId; + std::string errorMessage; bool const producesOutput = (ep->_outVariableNew != nullptr); result.reset(requestBlock(count, getPlanNode()->getRegisterPlan()->nrRegs[getPlanNode()->getDepth()])); @@ -454,6 +455,7 @@ AqlItemBlock* InsertBlock::work(std::vector& blocks) { // only copy 1st row of registers inherited from previous frame(s) inheritRegisters(res, result.get(), i, dstRow); + errorMessage.clear(); int errorCode = TRI_ERROR_NO_ERROR; if (!a.isObject()) { @@ -468,13 +470,16 @@ AqlItemBlock* InsertBlock::work(std::vector& blocks) { if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) { // return $NEW result->emplaceValue(dstRow, _outRegNew, opRes.slice().get("new")); - } + } + if (errorCode != TRI_ERROR_NO_ERROR) { + errorMessage.assign(opRes.errorMessage); + } } else { errorCode = TRI_ERROR_NO_ERROR; } } - handleResult(errorCode, ep->_options.ignoreErrors); + handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage); ++dstRow; } // done with a block @@ -605,6 +610,7 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { AqlValue const& a = res->getValueReference(i, docRegisterId); + errorMessage.clear(); int errorCode = TRI_ERROR_NO_ERROR; if (a.isObject()) { @@ -619,9 +625,9 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { } } else { errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; - errorMessage += std::string("expecting 'Object', got: ") + - a.slice().typeName() + std::string(" while handling: ") + - _exeNode->getTypeString(); + errorMessage = std::string("expecting 'Object', got: ") + + a.slice().typeName() + std::string(" while handling: ") + + _exeNode->getTypeString(); } if (errorCode == TRI_ERROR_NO_ERROR) { @@ -688,6 +694,12 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { // Ignore document not found on the DBserver: errorCode = TRI_ERROR_NO_ERROR; } + + if (errorCode != TRI_ERROR_NO_ERROR) { + errorMessage.assign(opRes.errorMessage); + } else { + errorMessage.clear(); + } handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage); ++dstRow; @@ -813,6 +825,7 @@ AqlItemBlock* UpsertBlock::work(std::vector& blocks) { // only copy 1st row of registers inherited from previous frame(s) inheritRegisters(res, result.get(), i, dstRow); + errorMessage.clear(); errorCode = TRI_ERROR_NO_ERROR; bool tookThis = false; @@ -842,7 +855,6 @@ AqlItemBlock* UpsertBlock::work(std::vector& blocks) { } else { updateBuilder = VPackCollection::merge(toUpdate, keyBuilder.slice(), false, false); } - } else { errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; } @@ -913,6 +925,11 @@ AqlItemBlock* UpsertBlock::work(std::vector& blocks) { if (producesOutput && errorCode == TRI_ERROR_NO_ERROR) { result->emplaceValue(dstRow - 1, _outRegNew, opRes.slice().get("new")); } + if (errorCode != TRI_ERROR_NO_ERROR) { + errorMessage.assign(opRes.errorMessage); + } else { + errorMessage.clear(); + } handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage); } } @@ -963,6 +980,11 @@ AqlItemBlock* UpsertBlock::work(std::vector& blocks) { // store $NEW result->emplaceValue(dstRow - 1, _outRegNew, opRes.slice().get("new")); } + if (errorCode != TRI_ERROR_NO_ERROR) { + errorMessage.assign(opRes.errorMessage); + } else { + errorMessage.clear(); + } handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage); } } @@ -1044,6 +1066,7 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { AqlValue const& a = res->getValueReference(i, docRegisterId); + errorMessage.clear(); int errorCode = TRI_ERROR_NO_ERROR; if (a.isObject()) { @@ -1058,9 +1081,9 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { } } else { errorCode = TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; - errorMessage += std::string("expecting 'Object', got: ") + - a.slice().typeName() + std::string(" while handling: ") + - _exeNode->getTypeString(); + errorMessage = std::string("expecting 'Object', got: ") + + a.slice().typeName() + std::string(" while handling: ") + + _exeNode->getTypeString(); } if (errorCode == TRI_ERROR_NO_ERROR) { @@ -1124,6 +1147,12 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { // Ignore document not found on the DBserver: errorCode = TRI_ERROR_NO_ERROR; } + + if (errorCode != TRI_ERROR_NO_ERROR) { + errorMessage.assign(opRes.errorMessage); + } else { + errorMessage.clear(); + } handleResult(errorCode, ep->_options.ignoreErrors, &errorMessage); ++dstRow; } else {