From 2bb58c386a1ac5053e57bb90a713b67bdddebc9a Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Tue, 20 Mar 2012 09:35:10 +0100 Subject: [PATCH] merged --- BasicsC/associative.c | 6 + BasicsC/string-buffer.c | 5 +- QL/optimize.c | 33 +- QL/parser.y | 2 +- Rest/HttpResponse.cpp | 131 ++-- Rest/HttpResponse.h | 30 +- RestHandler/RestDocumentHandler.cpp | 123 ++-- RestHandler/RestVocbaseBaseHandler.cpp | 152 +++-- RestHandler/RestVocbaseBaseHandler.h | 32 +- RestServer/ActionDispatcherThread.cpp | 1 + RestServer/AvocadoServer.cpp | 3 + RestServer/AvocadoServer.h | 2 +- RestServer/avocado.cpp | 1 - SkipLists/skiplist.c | 71 ++- SkipLists/skiplist.h | 15 + SkipLists/skiplistIndex.c | 40 +- .../rest_delete-document_spec.rb | 28 + .../RestDocuments/rest_read-document_spec.rb | 21 +- V8/v8-vocbase.cpp | 9 +- V8Client/shell.cpp | 3 + VocBase/document-collection.c | 9 +- VocBase/document-collection.h | 12 +- VocBase/query-base.h | 2 +- VocBase/query-cursor.c | 56 +- VocBase/query-cursor.h | 16 + VocBase/query-error.c | 79 --- VocBase/query-error.h | 249 -------- VocBase/query-parse.h | 2 +- VocBase/simple-collection.c | 16 +- VocBase/voc-error.h | 289 --------- VocBase/voc-errors.c | 62 ++ VocBase/voc-errors.h | 592 ++++++++++++++++++ VocBase/vocbase.c | 39 +- VocBase/vocbase.h | 2 +- js/actions/system/aql-cursor.js | 17 +- js/actions/system/aql-query.js | 6 +- js/common/bootstrap/errors.js | 52 ++ js/server/modules/actions.js | 10 +- js/server/tests/aql-bind.js | 123 +++- 39 files changed, 1411 insertions(+), 930 deletions(-) create mode 100644 UnitTests/RestDocuments/rest_delete-document_spec.rb delete mode 100644 VocBase/query-error.c delete mode 100644 VocBase/query-error.h delete mode 100644 VocBase/voc-error.h create mode 100644 VocBase/voc-errors.c create mode 100644 VocBase/voc-errors.h create mode 100644 js/common/bootstrap/errors.js diff --git a/BasicsC/associative.c b/BasicsC/associative.c index 53fad4218a..b6a56f4647 100644 --- a/BasicsC/associative.c +++ b/BasicsC/associative.c @@ -82,6 +82,7 @@ static void ResizeAssociativeArray (TRI_associative_array_t* array) { array->_nrResizes++; array->_table = TRI_Allocate(array->_nrAlloc * array->_elementSize); + // TODO: handle malloc failures for (j = 0; j < array->_nrAlloc; j++) { array->clearElement(array, array->_table + j * array->_elementSize); @@ -135,6 +136,7 @@ void TRI_InitAssociativeArray (TRI_associative_array_t* array, array->_nrAlloc = 10; array->_table = TRI_Allocate(array->_elementSize * array->_nrAlloc); + // TODO: handle malloc failures p = array->_table; e = p + array->_elementSize * array->_nrAlloc; @@ -528,6 +530,7 @@ static void ResizeAssociativePointer (TRI_associative_pointer_t* array) { array->_nrResizes++; array->_table = TRI_Allocate(array->_nrAlloc * sizeof(void*)); + // TODO: handle malloc failures for (j = 0; j < array->_nrAlloc; j++) { array->_table[j] = NULL; @@ -575,6 +578,7 @@ void TRI_InitAssociativePointer (TRI_associative_pointer_t* array, array->_nrAlloc = 10; array->_table = TRI_Allocate(sizeof(void*) * array->_nrAlloc); + // TODO: handle malloc failures p = array->_table; e = p + array->_nrAlloc; @@ -924,6 +928,7 @@ static void ResizeAssociativeSynced (TRI_associative_synced_t* array) { array->_nrResizes++; array->_table = TRI_Allocate(array->_nrAlloc * sizeof(void*)); + // TODO: handle malloc failures for (j = 0; j < array->_nrAlloc; j++) { array->_table[j] = NULL; @@ -971,6 +976,7 @@ void TRI_InitAssociativeSynced (TRI_associative_synced_t* array, array->_nrAlloc = 10; array->_table = TRI_Allocate(sizeof(void*) * array->_nrAlloc); + // TODO: handle malloc failures p = array->_table; e = p + array->_nrAlloc; diff --git a/BasicsC/string-buffer.c b/BasicsC/string-buffer.c index e26e6cc83f..a41175ac6b 100644 --- a/BasicsC/string-buffer.c +++ b/BasicsC/string-buffer.c @@ -68,16 +68,15 @@ static void Reserve (TRI_string_buffer_t * self, size_t size) { self->_len = (size_t)(1.2 * (self->_len + size)); self->_buffer = TRI_Reallocate(self->_buffer, self->_len + 1); - self->_current = self->_buffer + off; - - memset(self->_current, 0, Remaining(self) + 1); #if I_CARE_ABOUT_MALLOC_FAILURES if (NULL == self->_buffer) { abort(); } #endif + self->_current = self->_buffer + off; + memset(self->_current, 0, Remaining(self) + 1); } } diff --git a/QL/optimize.c b/QL/optimize.c index 443256fa6e..aa70c82cea 100644 --- a/QL/optimize.c +++ b/QL/optimize.c @@ -907,16 +907,13 @@ void QLOptimizeFreeRangeVector (TRI_vector_pointer_t* vector) { TRI_FreeString(range->_refValue._field); } - if (range->_valueType == RANGE_TYPE_JSON) { - // minValue and maxValue point to the same string, just free it once! - TRI_FreeString(range->_minValue._stringValue); - } - - if (range->_valueType == RANGE_TYPE_STRING) { + if (range->_valueType == RANGE_TYPE_JSON || + range->_valueType == RANGE_TYPE_STRING) { if (range->_minValue._stringValue) { TRI_FreeString(range->_minValue._stringValue); range->_minValue._stringValue = 0; } + if (range->_maxValue._stringValue) { TRI_FreeString(range->_maxValue._stringValue); range->_maxValue._stringValue = 0; @@ -1436,13 +1433,20 @@ static QL_optimize_range_t* QLOptimizeCreateRange (TRI_query_node_t* memberNode, } else if (range->_valueType == RANGE_TYPE_STRING) { range->_minValue._stringValue = TRI_DuplicateString(valueNode->_value._stringValue); + if (!range->_minValue._stringValue) { + TRI_Free(range); + return NULL; + } + range->_maxValue._stringValue = TRI_DuplicateString(valueNode->_value._stringValue); + if (!range->_maxValue._stringValue) { + TRI_Free(range); + return NULL; + } } else if (range->_valueType == RANGE_TYPE_JSON) { documentJs = TRI_InitQueryJavascript(); if (!documentJs) { - TRI_DestroyStringBuffer(name); - TRI_Free(name); TRI_Free(range); return NULL; } @@ -1450,9 +1454,16 @@ static QL_optimize_range_t* QLOptimizeCreateRange (TRI_query_node_t* memberNode, range->_minValue._stringValue = TRI_DuplicateString(documentJs->_buffer->_buffer); range->_maxValue._stringValue = TRI_DuplicateString(documentJs->_buffer->_buffer); TRI_FreeQueryJavascript(documentJs); - if (!range->_minValue._stringValue) { - TRI_DestroyStringBuffer(name); - TRI_Free(name); + + if (!range->_minValue._stringValue || !range->_maxValue._stringValue) { + if (range->_minValue._stringValue) { + TRI_FreeString(range->_minValue._stringValue); + } + + if (range->_maxValue._stringValue) { + TRI_FreeString(range->_maxValue._stringValue); + } + TRI_Free(range); return NULL; } diff --git a/QL/parser.y b/QL/parser.y index 059e0335bc..356c3391f0 100644 --- a/QL/parser.y +++ b/QL/parser.y @@ -16,10 +16,10 @@ #include #include +#include "VocBase/voc-errors.h" #include "VocBase/query-node.h" #include "VocBase/query-base.h" #include "VocBase/query-parse.h" -#include "VocBase/query-error.h" #define ABORT_IF_OOM(ptr) \ if (!ptr) { \ diff --git a/Rest/HttpResponse.cpp b/Rest/HttpResponse.cpp index 89c8b86848..6e35cae54c 100644 --- a/Rest/HttpResponse.cpp +++ b/Rest/HttpResponse.cpp @@ -119,33 +119,39 @@ namespace triagens { // ----------------------------------------------------------------------------- HttpResponse::HttpResponse () - : code(NOT_IMPLEMENTED), - headerFields(5), - bodyValue(), - freeables() { + : _code(NOT_IMPLEMENTED), + _headers(5), + _body(), + _isHeadResponse(false), + _bodySize(0), + _freeables() { } HttpResponse::HttpResponse (string const& header) - : code(NOT_IMPLEMENTED), - headerFields(5), - bodyValue(), - freeables() { + : _code(NOT_IMPLEMENTED), + _headers(5), + _body(), + _isHeadResponse(false), + _bodySize(0), + _freeables() { setHeaders(header, true); } HttpResponse::HttpResponse (HttpResponseCode code) - : code(code), - headerFields(5), - bodyValue(), - freeables() { + : _code(code), + _headers(5), + _body(), + _isHeadResponse(false), + _bodySize(0), + _freeables() { char* headerBuffer = StringUtils::duplicate("server\ntriagens GmbH High-Performance HTTP Server\n" "connection\nKeep-Alive\n" "content-type\ntext/plain;charset=utf-8\n"); - freeables.push_back(headerBuffer); + _freeables.push_back(headerBuffer); bool key = true; char* startKey = headerBuffer; @@ -161,7 +167,7 @@ namespace triagens { key = false; } else { - headerFields.insert(startKey, startValue); + _headers.insert(startKey, startValue); startKey = ptr + 1; startValue = 0; @@ -174,7 +180,7 @@ namespace triagens { HttpResponse::~HttpResponse () { - for (vector::iterator i = freeables.begin(); i != freeables.end(); ++i) { + for (vector::iterator i = _freeables.begin(); i != _freeables.end(); ++i) { delete[] (*i); } } @@ -183,6 +189,10 @@ namespace triagens { // HttpResponse methods // ----------------------------------------------------------------------------- + HttpResponse::HttpResponseCode HttpResponse::responseCode () { + return _code; + } + void HttpResponse::setContentType (string const& contentType) { setHeader("content-type", contentType); } @@ -190,20 +200,25 @@ namespace triagens { size_t HttpResponse::contentLength () { - char const* const* i = headerFields.lookup("content-length"); - - if (i == 0) { - return 0; + if (_isHeadResponse) { + return _bodySize; } + else { + char const* const* i = _headers.lookup("content-length"); - return StringUtils::uint32(*i); + if (i == 0) { + return 0; + } + + return StringUtils::uint32(*i); + } } string HttpResponse::header (string const& key) const { string k = StringUtils::tolower(key); - char const* const* i = headerFields.lookup(k.c_str()); + char const* const* i = _headers.lookup(k.c_str()); if (i == 0) { return ""; @@ -217,7 +232,7 @@ namespace triagens { string HttpResponse::header (string const& key, bool& found) const { string k = StringUtils::tolower(key); - char const* const* i = headerFields.lookup(k.c_str()); + char const* const* i = _headers.lookup(k.c_str()); if (i == 0) { found = false; @@ -237,7 +252,7 @@ namespace triagens { map result; - for (headerFields.range(begin, end); begin < end; ++begin) { + for (_headers.range(begin, end); begin < end; ++begin) { char const* key = begin->_key; if (key == 0) { @@ -256,7 +271,7 @@ namespace triagens { string lk = StringUtils::tolower(key); if (value.empty()) { - headerFields.erase(lk.c_str()); + _headers.erase(lk.c_str()); } else { StringUtils::trimInPlace(lk); @@ -264,10 +279,10 @@ namespace triagens { char const* k = StringUtils::duplicate(lk); char const* v = StringUtils::duplicate(value); - headerFields.insert(k, lk.size(), v); + _headers.insert(k, lk.size(), v); - freeables.push_back(k); - freeables.push_back(v); + _freeables.push_back(k); + _freeables.push_back(v); } } @@ -279,7 +294,7 @@ namespace triagens { char* headerBuffer = new char[headers.size() + 1]; memcpy(headerBuffer, headers.c_str(), headers.size() + 1); - freeables.push_back(headerBuffer); + _freeables.push_back(headerBuffer); // check for '\n' (we check for '\r' later) int lineNum = includeLine0 ? 0 : 1; @@ -322,14 +337,14 @@ namespace triagens { if (start2 < end2) { *end2 = '\0'; - code = static_cast(::atoi(start2)); + _code = static_cast(::atoi(start2)); } else { - code = NOT_IMPLEMENTED; + _code = NOT_IMPLEMENTED; } } else { - code = NOT_IMPLEMENTED; + _code = NOT_IMPLEMENTED; } } @@ -354,10 +369,10 @@ namespace triagens { *end4 = '\0'; - headerFields.insert(start, end3 - start, start2); + _headers.insert(start, end3 - start, start2); } else { - headerFields.insert(start, end3 - start, end3); + _headers.insert(start, end3 - start, end3); } } } @@ -374,11 +389,19 @@ namespace triagens { HttpResponse* HttpResponse::swap () { - HttpResponse* response = new HttpResponse(code); + HttpResponse* response = new HttpResponse(_code); - response->headerFields.swap(&headerFields); - response->bodyValue.swap(&bodyValue); - response->freeables.swap(freeables); + response->_headers.swap(&_headers); + response->_body.swap(&_body); + response->_freeables.swap(_freeables); + + bool isHeadResponse = response->_isHeadResponse; + response->_isHeadResponse = _isHeadResponse; + _isHeadResponse = isHeadResponse; + + size_t bodySize = response->_bodySize; + response->_bodySize = _bodySize; + _bodySize = bodySize; return response; } @@ -387,7 +410,7 @@ namespace triagens { void HttpResponse::writeHeader (StringBuffer* output) { output->appendText("HTTP/1.1 "); - output->appendText(responseString(code)); + output->appendText(responseString(_code)); output->appendText("\r\n"); basics::Dictionary::KeyValue const* begin; @@ -396,7 +419,7 @@ namespace triagens { bool seenTransferEncoding = false; string transferEncoding; - for (headerFields.range(begin, end); begin < end; ++begin) { + for (_headers.range(begin, end); begin < end; ++begin) { char const* key = begin->_key; if (key == 0) { @@ -433,7 +456,14 @@ namespace triagens { } output->appendText("content-length: "); - output->appendInteger(static_cast(bodyValue.length())); + + if (_isHeadResponse) { + output->appendInteger(_bodySize); + } + else { + output->appendInteger(_body.length()); + } + output->appendText("\r\n"); } @@ -442,8 +472,27 @@ namespace triagens { + size_t HttpResponse::bodySize () { + if (_isHeadResponse) { + return _bodySize; + } + else { + return _body.length(); + } + } + + + StringBuffer& HttpResponse::body () { - return bodyValue; + return _body; + } + + + + void HttpResponse::headResponse (size_t size) { + _body.clear(); + _isHeadResponse = true; + _bodySize = size; } } } diff --git a/Rest/HttpResponse.h b/Rest/HttpResponse.h index 143b26e82e..d27cf5a50b 100644 --- a/Rest/HttpResponse.h +++ b/Rest/HttpResponse.h @@ -180,9 +180,7 @@ namespace triagens { /// @brief returns the response code //////////////////////////////////////////////////////////////////////////////// - HttpResponseCode responseCode () { - return code; - } + HttpResponseCode responseCode (); //////////////////////////////////////////////////////////////////////////////// /// @brief returns the content length @@ -258,6 +256,12 @@ namespace triagens { void writeHeader (basics::StringBuffer*); + //////////////////////////////////////////////////////////////////////////////// + /// @brief returns the size of the body + //////////////////////////////////////////////////////////////////////////////// + + size_t bodySize (); + //////////////////////////////////////////////////////////////////////////////// /// @brief returns the body /// @@ -270,13 +274,25 @@ namespace triagens { basics::StringBuffer& body (); + //////////////////////////////////////////////////////////////////////////////// + /// @brief returns the body + /// + /// In case of HEAD request, no body must be defined. However, the response + /// needs to know the size of body. + //////////////////////////////////////////////////////////////////////////////// + + void headResponse (size_t); + private: - HttpResponseCode code; + HttpResponseCode _code; - basics::Dictionary headerFields; - basics::StringBuffer bodyValue; + basics::Dictionary _headers; + basics::StringBuffer _body; - vector freeables; + bool _isHeadResponse; + size_t _bodySize; + + vector _freeables; }; } } diff --git a/RestHandler/RestDocumentHandler.cpp b/RestHandler/RestDocumentHandler.cpp index 1ae4c622df..2dbd7f3385 100644 --- a/RestHandler/RestDocumentHandler.cpp +++ b/RestHandler/RestDocumentHandler.cpp @@ -180,10 +180,11 @@ HttpHandler::status_e RestDocumentHandler::execute () { /// then a @LIT{HTTP 400} is returned and the body of the response contains /// an error document. /// -/// @REST{POST /document?collection=@FA{collection-identifier}&createCollection=@FA{create}} +/// @REST{POST /document?collection=@FA{collection-name}&createCollection=@FA{create}} /// -/// Instead of a @FA{collection-identifier}, a collection name can be used. If -/// @FA{create} is true, then the collection is created if it does not exists. +/// Instead of a @FA{collection-identifier}, a @FA{collection-name} can be +/// used. If @FA{createCollection} is true, then the collection is created if it does not +/// exists. /// /// @EXAMPLES /// @@ -368,11 +369,8 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) { vector const& suffix = request->suffix(); /// check for an etag - string ifNoneMatch = request->header("if-none-match"); - TRI_voc_rid_t ifNoneRid = parseEtag(ifNoneMatch); - - string ifMatch = request->header("if-match"); - TRI_voc_rid_t ifRid = parseEtag(ifMatch); + TRI_voc_rid_t ifNoneRid = extractRevision("if-none-match"); + TRI_voc_rid_t ifRid = extractRevision("if-match", "_rev"); // split the document reference string cid = suffix[0]; @@ -415,7 +413,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) { generateDocument(document, generateBody); } else { - generatePreconditionFailed(); + generatePreconditionFailed(_documentCollection->base._cid, document->_did, rid); } } else if (ifNoneRid == rid) { @@ -426,7 +424,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) { generateNotModified(StringUtils::itoa(rid)); } else { - generatePreconditionFailed(); + generatePreconditionFailed(_documentCollection->base._cid, document->_did, rid); } } else { @@ -437,7 +435,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) { generateDocument(document, generateBody); } else { - generatePreconditionFailed(); + generatePreconditionFailed(_documentCollection->base._cid, document->_did, rid); } } @@ -460,8 +458,10 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) { //////////////////////////////////////////////////////////////////////////////// bool RestDocumentHandler::readAllDocuments () { -#ifdef FIXME - vector const& suffix = request->suffix(); + + // extract the cid + bool found; + string cid = request->value("collection", found); // find and load collection given by name oder identifier bool ok = findCollection(cid) && loadCollection(); @@ -534,7 +534,6 @@ bool RestDocumentHandler::readAllDocuments () { response->body().appendText(TRI_BeginStringBuffer(&buffer), TRI_LengthStringBuffer(&buffer)); TRI_AnnihilateStringBuffer(&buffer); -#endif return true; } @@ -554,16 +553,16 @@ bool RestDocumentHandler::readAllDocuments () { //////////////////////////////////////////////////////////////////////////////// bool RestDocumentHandler::checkDocument () { -#ifdef FIXME vector const& suffix = request->suffix(); - if (suffix.size() != 1) { - generateError(HttpResponse::BAD, "expecting URI /document/"); + if (suffix.size() != 2) { + generateError(HttpResponse::BAD, + TRI_REST_ERROR_BAD_PARAMETER, + "expecting URI /document/"); return false; } return readSingleDocument(false); -#endif } //////////////////////////////////////////////////////////////////////////////// @@ -629,19 +628,19 @@ bool RestDocumentHandler::checkDocument () { //////////////////////////////////////////////////////////////////////////////// bool RestDocumentHandler::updateDocument () { -#ifdef FIXME vector const& suffix = request->suffix(); - // split the document reference - string cid; - string did; - - ok = splitDocumentReference(suffix[1], cid, did); - - if (! ok) { + if (suffix.size() != 2) { + generateError(HttpResponse::BAD, + TRI_REST_ERROR_BAD_PARAMETER, + "expecting UPDATE /document/"); return false; } + // split the document reference + string cid = suffix[0]; + string didStr = suffix[1]; + // find and load collection given by name oder identifier bool ok = findCollection(cid) && loadCollection(); @@ -660,7 +659,7 @@ bool RestDocumentHandler::updateDocument () { TRI_voc_did_t did = StringUtils::uint64(didStr); // extract the revision - TRI_voc_rid_t revision = extractRevision(); + TRI_voc_rid_t revision = extractRevision("if-match", "_rev"); // extract or chose the update policy TRI_doc_update_policy_e policy = extractUpdatePolicy(); @@ -672,40 +671,39 @@ bool RestDocumentHandler::updateDocument () { _documentCollection->beginWrite(_documentCollection); // unlocking is performed in updateJson() - TRI_doc_mptr_t const* mptr = _documentCollection->updateJson(_documentCollection, json, did, revision, policy, true); TRI_voc_rid_t rid = 0; - - if (mptr != 0) { - rid = mptr->_rid; - } + TRI_doc_mptr_t const* mptr = _documentCollection->updateJson(_documentCollection, json, did, revision, &rid, policy, true); // ............................................................................. // outside write transaction // ............................................................................. if (mptr != 0) { - generateOk(_documentCollection->base._cid, did, rid); + generateUpdated(_documentCollection->base._cid, did, mptr->_rid); return true; } else { if (TRI_errno() == TRI_VOC_ERROR_READ_ONLY) { - generateError(HttpResponse::FORBIDDEN, "collection is read-only"); + generateError(HttpResponse::FORBIDDEN, + TRI_VOC_ERROR_READ_ONLY, + "collection is read-only"); return false; } else if (TRI_errno() == TRI_VOC_ERROR_DOCUMENT_NOT_FOUND) { - generateDocumentNotFound(suffix[0], didStr); + generateDocumentNotFound(cid + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + didStr); return false; } else if (TRI_errno() == TRI_VOC_ERROR_CONFLICT) { - generateConflict(suffix[0], didStr); + generatePreconditionFailed(_documentCollection->base._cid, did, rid); return false; } else { - generateError(HttpResponse::SERVER_ERROR, "cannot update, failed with " + string(TRI_last_error())); + generateError(HttpResponse::SERVER_ERROR, + TRI_ERROR_INTERNAL, + "cannot update, failed with " + string(TRI_last_error())); return false; } } -#endif } //////////////////////////////////////////////////////////////////////////////// @@ -713,9 +711,8 @@ bool RestDocumentHandler::updateDocument () { /// /// @REST{DELETE /document/@FA{document-handle}} /// -/// Deletes the document identified by @FA{document-handle} from the collection -/// identified by @FA{collection-identifier}. If the document exists and could -/// be deleted, then a @LIT{HTTP 204} is returned. +/// Deletes the document identified by @FA{document-handle}. If the document +/// exists and could be deleted, then a @LIT{HTTP 204} is returned. /// /// The body of the response contains a JSON object with the information about /// the handle and the revision. The attribute @LIT{_id} contains the known @@ -727,7 +724,7 @@ bool RestDocumentHandler::updateDocument () { /// /// If an etag is supplied in the "If-Match" field, then the AvocadoDB checks /// that the revision of the document is equal to the tag. If there is a -/// mismatch, then a @LIT{HTTP 409} conflict is returned and no delete is +/// mismatch, then a @LIT{HTTP 412} conflict is returned and no delete is /// performed. /// /// @REST{DELETE /document/@FA{document-handle}?policy=@FA{policy}} @@ -737,9 +734,9 @@ bool RestDocumentHandler::updateDocument () { /// /// @REST{DELETE /document/@FA{document-handle}?rev=@FA{etag}} /// -/// You can also supply the etag using the parameter @LIT{rev} instead of an "ETag" -/// header. You must never supply both the "ETag" header and the @LIT{rev} -/// parameter. +/// You can also supply the etag using the parameter @LIT{rev} instead of an +/// "If-Match" header. You must never supply both the "If-Match" header and the +/// @LIT{rev} parameter. /// /// @EXAMPLES /// @@ -757,19 +754,21 @@ bool RestDocumentHandler::updateDocument () { //////////////////////////////////////////////////////////////////////////////// bool RestDocumentHandler::deleteDocument () { -#ifdef FIXME vector const& suffix = request->suffix(); - // split the document reference - string didStr; - ok = splitDocumentReference(suffix[1], didStr); - - if (! ok) { + if (suffix.size() != 2) { + generateError(HttpResponse::BAD, + TRI_REST_ERROR_BAD_PARAMETER, + "expecting DELETE /document/"); return false; } + // split the document reference + string cid = suffix[0]; + string didStr = suffix[1]; + // find and load collection given by name oder identifier - bool ok = findCollection(cid[0]) && loadCollection(); + bool ok = findCollection(cid) && loadCollection(); if (! ok) { return false; @@ -779,7 +778,7 @@ bool RestDocumentHandler::deleteDocument () { TRI_voc_did_t did = StringUtils::uint64(didStr); // extract the revision - TRI_voc_rid_t revision = extractRevision(); + TRI_voc_rid_t revision = extractRevision("if-match", "_rev"); // extract or chose the update policy TRI_doc_update_policy_e policy = extractUpdatePolicy(); @@ -791,35 +790,39 @@ bool RestDocumentHandler::deleteDocument () { _documentCollection->beginWrite(_documentCollection); // unlocking is performed in destroy() - ok = _documentCollection->destroy(_documentCollection, did, revision, policy, true); + TRI_voc_rid_t rid = 0; + ok = _documentCollection->destroy(_documentCollection, did, revision, &rid, policy, true); // ............................................................................. // outside write transaction // ............................................................................. if (ok) { - generateOk(); + generateDeleted(_documentCollection->base._cid, did, rid); return true; } else { if (TRI_errno() == TRI_VOC_ERROR_READ_ONLY) { - generateError(HttpResponse::FORBIDDEN, "collection is read-only"); + generateError(HttpResponse::FORBIDDEN, + TRI_VOC_ERROR_READ_ONLY, + "collection is read-only"); return false; } else if (TRI_errno() == TRI_VOC_ERROR_DOCUMENT_NOT_FOUND) { - generateDocumentNotFound(suffix[0], didStr); + generateDocumentNotFound(cid + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + didStr); return false; } else if (TRI_errno() == TRI_VOC_ERROR_CONFLICT) { - generateConflict(suffix[0], didStr); + generatePreconditionFailed(_documentCollection->base._cid, did, rid); return false; } else { - generateError(HttpResponse::SERVER_ERROR, "cannot delete, failed with " + string(TRI_last_error())); + generateError(HttpResponse::SERVER_ERROR, + TRI_ERROR_INTERNAL, + "cannot delete, failed with " + string(TRI_last_error())); return false; } } -#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/RestHandler/RestVocbaseBaseHandler.cpp b/RestHandler/RestVocbaseBaseHandler.cpp index 578356c017..ada8d39555 100644 --- a/RestHandler/RestVocbaseBaseHandler.cpp +++ b/RestHandler/RestVocbaseBaseHandler.cpp @@ -143,17 +143,7 @@ void RestVocbaseBaseHandler::generateOk () { } //////////////////////////////////////////////////////////////////////////////// -/// @brief generates ok message without content -//////////////////////////////////////////////////////////////////////////////// - -void RestVocbaseBaseHandler::generateOk (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t rid) { - response = new HttpResponse(HttpResponse::NO_CONTENT); - - response->setHeader("ETag", "\"" + StringUtils::itoa(rid) + "\""); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief generates created message without content but a location header +/// @brief generates created message //////////////////////////////////////////////////////////////////////////////// void RestVocbaseBaseHandler::generateCreated (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) { @@ -177,7 +167,7 @@ void RestVocbaseBaseHandler::generateCreated (TRI_voc_cid_t cid, TRI_voc_did_t d } //////////////////////////////////////////////////////////////////////////////// -/// @brief generates accepted message without content but a location header +/// @brief generates accepted message //////////////////////////////////////////////////////////////////////////////// void RestVocbaseBaseHandler::generateAccepted (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) { @@ -200,6 +190,50 @@ void RestVocbaseBaseHandler::generateAccepted (TRI_voc_cid_t cid, TRI_voc_did_t .appendText("}"); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates deleted message +//////////////////////////////////////////////////////////////////////////////// + +void RestVocbaseBaseHandler::generateDeleted (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) { + string cidStr = StringUtils::itoa(cid); + string didStr = StringUtils::itoa(did); + string ridStr = StringUtils::itoa(rid); + string handle = cidStr + "/" + didStr; + + response = new HttpResponse(HttpResponse::OK); + + response->setContentType("application/json; charset=utf-8"); + + response->body() + .appendText("{\"error\":false,\"_id\":\"") + .appendText(handle.c_str()) + .appendText("\",\"_rev\":") + .appendInteger(rid) + .appendText("}"); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates updated message +//////////////////////////////////////////////////////////////////////////////// + +void RestVocbaseBaseHandler::generateUpdated (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) { + string cidStr = StringUtils::itoa(cid); + string didStr = StringUtils::itoa(did); + string ridStr = StringUtils::itoa(rid); + string handle = cidStr + "/" + didStr; + + response = new HttpResponse(HttpResponse::OK); + + response->setContentType("application/json; charset=utf-8"); + + response->body() + .appendText("{\"error\":false,\"_id\":\"") + .appendText(handle.c_str()) + .appendText("\",\"_rev\":") + .appendInteger(rid) + .appendText("}"); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief generates collection not found error message //////////////////////////////////////////////////////////////////////////////// @@ -244,8 +278,16 @@ void RestVocbaseBaseHandler::generateNotImplemented (string const& path) { /// @brief generates precondition failed //////////////////////////////////////////////////////////////////////////////// -void RestVocbaseBaseHandler::generatePreconditionFailed () { +void RestVocbaseBaseHandler::generatePreconditionFailed (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) { response = new HttpResponse(HttpResponse::PRECONDITION_FAILED); + response->setContentType("application/json; charset=utf-8"); + + response->body() + .appendText("{\"error\":true,\"_id\":\"") + .appendInteger(cid).appendChar(TRI_DOCUMENT_HANDLE_SEPARATOR_CHR).appendInteger(did) + .appendText("\",\"_rev\":") + .appendInteger(rid) + .appendText("}"); } //////////////////////////////////////////////////////////////////////////////// @@ -274,37 +316,36 @@ void RestVocbaseBaseHandler::generateDocument (TRI_doc_mptr_t const* document, // add document identifier to buffer TRI_string_buffer_t buffer; - if (generateDocument) { - string id = StringUtils::itoa(_documentCollection->base._cid) + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + StringUtils::itoa(document->_did); + string id = StringUtils::itoa(_documentCollection->base._cid) + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + StringUtils::itoa(document->_did); - TRI_json_t augmented; + TRI_json_t augmented; + TRI_InitArrayJson(&augmented); - TRI_InitArrayJson(&augmented); + TRI_json_t* _id = TRI_CreateStringCopyJson(id.c_str()); - TRI_json_t* _id = TRI_CreateStringCopyJson(id.c_str()); + if (_id) { + TRI_Insert2ArrayJson(&augmented, "_id", _id); + } - if (_id) { - TRI_Insert2ArrayJson(&augmented, "_id", _id); - } + TRI_json_t* _rev = TRI_CreateNumberJson(document->_rid); - TRI_json_t* _rev = TRI_CreateNumberJson(document->_rid); + if (_rev) { + TRI_Insert2ArrayJson(&augmented, "_rev", _rev); + } - if (_rev) { - TRI_Insert2ArrayJson(&augmented, "_rev", _rev); - } + // convert object to string + TRI_InitStringBuffer(&buffer); - // convert object to string - TRI_InitStringBuffer(&buffer); + TRI_StringifyAugmentedShapedJson(_documentCollection->_shaper, &buffer, &document->_document, &augmented); - TRI_StringifyAugmentedShapedJson(_documentCollection->_shaper, &buffer, &document->_document, &augmented); + TRI_DestroyJson(&augmented); - TRI_DestroyJson(&augmented); - if (_id) { - TRI_Free(_id); - } - if (_rev) { - TRI_Free(_rev); - } + if (_id) { + TRI_Free(_id); + } + + if (_rev) { + TRI_Free(_rev); } // and generate a response @@ -314,18 +355,21 @@ void RestVocbaseBaseHandler::generateDocument (TRI_doc_mptr_t const* document, if (generateDocument) { response->body().appendText(TRI_BeginStringBuffer(&buffer), TRI_LengthStringBuffer(&buffer)); - - TRI_AnnihilateStringBuffer(&buffer); } + else { + response->headResponse(TRI_LengthStringBuffer(&buffer)); + } + + TRI_AnnihilateStringBuffer(&buffer); } //////////////////////////////////////////////////////////////////////////////// /// @brief extracts the revision //////////////////////////////////////////////////////////////////////////////// -TRI_voc_rid_t RestVocbaseBaseHandler::extractRevision () { +TRI_voc_rid_t RestVocbaseBaseHandler::extractRevision (string const& header, string const& parameter) { bool found; - string etag = request->header("etag", found); + string etag = StringUtils::trim(request->header(header, found)); if (found && ! etag.empty() && etag[0] == '"' && etag[etag.length()-1] == '"') { return StringUtils::uint64(etag.c_str() + 1, etag.length() - 2); @@ -334,13 +378,18 @@ TRI_voc_rid_t RestVocbaseBaseHandler::extractRevision () { return 0; } - etag = request->value("_rev", found); - - if (found) { - return StringUtils::uint64(etag.c_str() + 1, etag.length() - 2); + if (parameter.empty()) { + return 0; } else { - return 0; + etag = request->value(parameter, found); + + if (found) { + return StringUtils::uint64(etag.c_str() + 1, etag.length() - 2); + } + else { + return 0; + } } } @@ -537,21 +586,6 @@ TRI_doc_mptr_t const* RestVocbaseBaseHandler::findDocument (string const& doc) { return document; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief converts an etag field -//////////////////////////////////////////////////////////////////////////////// - -TRI_voc_rid_t RestVocbaseBaseHandler::parseEtag (string const& etag) { - string trim = StringUtils::trim(etag); - size_t len = trim.size(); - - if (len < 2 || trim[0] != '"' || trim[len-1] != '"') { - return 0; - } - - return StringUtils::int64(trim.substr(1, len-2)); -} - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/RestHandler/RestVocbaseBaseHandler.h b/RestHandler/RestVocbaseBaseHandler.h index 586cd87eed..297b8f1fe3 100644 --- a/RestHandler/RestVocbaseBaseHandler.h +++ b/RestHandler/RestVocbaseBaseHandler.h @@ -146,23 +146,29 @@ namespace triagens { void generateOk (); //////////////////////////////////////////////////////////////////////////////// -/// @brief generates ok message without content -//////////////////////////////////////////////////////////////////////////////// - - void generateOk (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t rid); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief generates created message without content but a location header +/// @brief generates created message //////////////////////////////////////////////////////////////////////////////// void generateCreated (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t); //////////////////////////////////////////////////////////////////////////////// -/// @brief generates accepted message without content but a location header +/// @brief generates accepted message //////////////////////////////////////////////////////////////////////////////// void generateAccepted (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t); +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates deleted message +//////////////////////////////////////////////////////////////////////////////// + + void generateDeleted (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates updated message +//////////////////////////////////////////////////////////////////////////////// + + void generateUpdated (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t); + //////////////////////////////////////////////////////////////////////////////// /// @brief generates collection not found error message //////////////////////////////////////////////////////////////////////////////// @@ -191,7 +197,7 @@ namespace triagens { /// @brief generates precondition failed //////////////////////////////////////////////////////////////////////////////// - void generatePreconditionFailed (); + void generatePreconditionFailed (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t); //////////////////////////////////////////////////////////////////////////////// /// @brief generates not modified @@ -209,7 +215,7 @@ namespace triagens { /// @brief extracts the revision //////////////////////////////////////////////////////////////////////////////// - TRI_voc_rid_t extractRevision (); + TRI_voc_rid_t extractRevision (string const& header, string const& parameter = ""); //////////////////////////////////////////////////////////////////////////////// /// @brief extracts the update policy @@ -241,12 +247,6 @@ namespace triagens { TRI_doc_mptr_t const* findDocument (string const& doc); -//////////////////////////////////////////////////////////////////////////////// -/// @brief converts an etag field -//////////////////////////////////////////////////////////////////////////////// - - TRI_voc_rid_t parseEtag (string const& etag); - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/RestServer/ActionDispatcherThread.cpp b/RestServer/ActionDispatcherThread.cpp index 313ebe2ec6..63ac57008e 100644 --- a/RestServer/ActionDispatcherThread.cpp +++ b/RestServer/ActionDispatcherThread.cpp @@ -229,6 +229,7 @@ void ActionDispatcherThread::initialise () { bool ok; char const* files[] = { "common/bootstrap/modules.js", "common/bootstrap/print.js", + "common/bootstrap/errors.js", "server/server.js" }; size_t i; diff --git a/RestServer/AvocadoServer.cpp b/RestServer/AvocadoServer.cpp index 8f1b1bd4af..5de35afb30 100644 --- a/RestServer/AvocadoServer.cpp +++ b/RestServer/AvocadoServer.cpp @@ -67,6 +67,7 @@ using namespace triagens::avocado; #include "js/common/bootstrap/js-modules.h" #include "js/common/bootstrap/js-print.h" +#include "js/common/bootstrap/js-errors.h" #include "js/server/js-server.h" // ----------------------------------------------------------------------------- @@ -397,6 +398,7 @@ void AvocadoServer::buildApplicationServer () { LOGGER_INFO << "using built-in JavaScript startup files"; StartupLoader.defineScript("common/bootstrap/modules.js", JS_common_bootstrap_modules); StartupLoader.defineScript("common/bootstrap/print.js", JS_common_bootstrap_print); + StartupLoader.defineScript("common/bootstrap/errors.js", JS_common_bootstrap_errors); StartupLoader.defineScript("server/server.js", JS_server_server); } else { @@ -629,6 +631,7 @@ void AvocadoServer::executeShell () { bool ok; char const* files[] = { "common/bootstrap/modules.js", "common/bootstrap/print.js", + "common/bootstrap/errors.js", "server/server.js" }; size_t i; diff --git a/RestServer/AvocadoServer.h b/RestServer/AvocadoServer.h index 15584c2065..76561d01e4 100644 --- a/RestServer/AvocadoServer.h +++ b/RestServer/AvocadoServer.h @@ -33,7 +33,7 @@ #include "Admin/ApplicationAdminServer.h" #include "HttpServer/ApplicationHttpServer.h" #include "VocBase/vocbase.h" -#include "VocBase/query-error.h" +#include "VocBase/voc-errors.h" // ----------------------------------------------------------------------------- // --SECTION-- class AvocadoServer diff --git a/RestServer/avocado.cpp b/RestServer/avocado.cpp index 42ebb6b68d..d1f66196e1 100644 --- a/RestServer/avocado.cpp +++ b/RestServer/avocado.cpp @@ -51,7 +51,6 @@ using namespace triagens::avocado; int main (int argc, char* argv[]) { TRIAGENS_RESULT_GENERATOR_INITIALISE; TRI_InitialiseVocBase(); - TRI_InitialiseQueryErrors(); // create and start a AvocadoDB server AvocadoServer server(argc, argv); diff --git a/SkipLists/skiplist.c b/SkipLists/skiplist.c index c2ec8834fd..0ec79ab8ec 100755 --- a/SkipLists/skiplist.c +++ b/SkipLists/skiplist.c @@ -1094,7 +1094,7 @@ bool TRI_RemoveElementSkipList (TRI_skiplist_t* skiplist, void* element, void* o // Use the callback to determine if the element is less or greater than // the next node element. // ....................................................................... - compareResult = skiplist->compareElementElement(skiplist,element,&(nextNode->_element), 0); + compareResult = skiplist->compareElementElement(skiplist,element,&(nextNode->_element), -1); // ....................................................................... // We have found the item! @@ -1354,6 +1354,7 @@ void TRI_InitSkipListMulti (TRI_skiplist_multi_t* skiplist, size_t elementSize, int (*compareElementElement) (TRI_skiplist_multi_t*, void*, void*, int), int (*compareKeyElement) (TRI_skiplist_multi_t*, void*, void*, int), + bool (*equalElementElement) (TRI_skiplist_multi_t*, void*, void*), TRI_skiplist_prob_e probability, uint32_t maximumHeight) { @@ -1367,6 +1368,7 @@ void TRI_InitSkipListMulti (TRI_skiplist_multi_t* skiplist, skiplist->compareElementElement = compareElementElement; skiplist->compareKeyElement = compareKeyElement; + skiplist->equalElementElement = equalElementElement; // .......................................................................... // Assign the maximum height of the skip list. This maximum height must be @@ -1827,6 +1829,10 @@ bool TRI_InsertElementSkipListMulti(TRI_skiplist_multi_t* skiplist, void* elemen // We do not allow non-unique elements. // ....................................................................... if (compareResult == 0) { + /* start oreste: */ + assert(false); + /* end oreste: */ + if (overwrite) { memcpy(&(nextNode->_element),element,skiplist->_base._elementSize); TRI_FreeSkipListNode(&(skiplist->_base), newNode); @@ -1878,7 +1884,6 @@ bool TRI_InsertElementSkipListMulti(TRI_skiplist_multi_t* skiplist, void* elemen // SKIPLIST_ABSOLUTE_MAX_HEIGHT number of elements. // .......................................................................... - for (j = 0; j < newHeight; ++j) { tempLeftNode = newNode->_column[j]._prev; tempRightNode = tempLeftNode->_column[j]._next; @@ -1897,6 +1902,7 @@ bool TRI_InsertElementSkipListMulti(TRI_skiplist_multi_t* skiplist, void* elemen */ } + return true; } @@ -2026,12 +2032,12 @@ bool TRI_RemoveElementSkipListMulti (TRI_skiplist_multi_t* skiplist, void* eleme // Use the callback to determine if the element is less or greater than // the next node element. // ....................................................................... - compareResult = skiplist->compareElementElement(skiplist,element,&(nextNode->_element), -1); + compareResult = skiplist->compareElementElement(skiplist,element,&(nextNode->_element), TRI_SKIPLIST_COMPARE_SLIGHTLY_LESS); // ....................................................................... // We have found an item which matches the key // ....................................................................... - if (compareResult == 0) { + if (compareResult == TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL) { currentNode = nextNode; goto END; } @@ -2051,7 +2057,23 @@ bool TRI_RemoveElementSkipListMulti (TRI_skiplist_multi_t* skiplist, void* eleme // We have reached the lowest level of the lists -- no such item. // ....................................................................... if (currentLevel == 0) { - return false; + + // ..................................................................... + // The element could not be located + // ..................................................................... + if (compareResult == TRI_SKIPLIST_COMPARE_STRICTLY_LESS) { + return false; + } + + // ..................................................................... + // The element could be located and we are at the lowest level + // ..................................................................... + if (compareResult == TRI_SKIPLIST_COMPARE_SLIGHTLY_LESS) { + goto END; + } + + // can not occur + assert(false); } // ....................................................................... @@ -2066,16 +2088,41 @@ bool TRI_RemoveElementSkipListMulti (TRI_skiplist_multi_t* skiplist, void* eleme END: + // .......................................................................... + // locate the correct elemet -- since we allow duplicates + // .......................................................................... + while (currentNode != NULL) { + if (skiplist->equalElementElement(skiplist, element, &(currentNode->_element))) { + break; + } + currentNode = TRI_NextNodeBaseSkipList(&(skiplist->_base), currentNode); + } + + + // .......................................................................... + // The actual element could not be located - an element with a matching key + // may exist, but the same data stored within the element could not be located + // .......................................................................... + + if (currentNode == NULL) { + return false; + } + + // .......................................................................... + // Perhaps the user wants a copy before we destory the data? + // .......................................................................... + if (old != NULL) { memcpy(old, &(currentNode->_element), skiplist->_base._elementSize); } - + + // .......................................................................... - // remove element + // remove element // .......................................................................... - + for (j = 0; j < currentNode->_colLength; ++j) { tempLeftNode = currentNode->_column[j]._prev; tempRightNode = currentNode->_column[j]._next; @@ -2185,16 +2232,14 @@ void* TRI_RightLookupByKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* ke // Use the callback to determine if the element is less or greater than // the next node element. // ....................................................................... - compareResult = skiplist->compareKeyElement(skiplist,key,&(prevNode->_element), 0); + compareResult = skiplist->compareKeyElement(skiplist,key,&(prevNode->_element), 1); // ....................................................................... - // We have found the item! + // We have found the item! Not possible since we are searching by key! // ....................................................................... if (compareResult == 0) { - //return &(nextNode->_element); - //return currentNode; - return prevNode->_column[0]._next; + assert(false); } // ....................................................................... diff --git a/SkipLists/skiplist.h b/SkipLists/skiplist.h index 520b1c9087..7eafbd3405 100755 --- a/SkipLists/skiplist.h +++ b/SkipLists/skiplist.h @@ -60,6 +60,14 @@ typedef enum { TRI_skiplist_prob_e; +typedef enum { + TRI_SKIPLIST_COMPARE_STRICTLY_LESS = -1, + TRI_SKIPLIST_COMPARE_STRICTLY_GREATER = 1, + TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL = 0, + TRI_SKIPLIST_COMPARE_SLIGHTLY_LESS = -2, + TRI_SKIPLIST_COMPARE_SLIGHTLY_GREATER = 2 +} +TRI_skiplist_compare_e; //////////////////////////////////////////////////////////////////////////////// /// @brief storage structure for a node's nearest neighbours @@ -340,6 +348,12 @@ typedef struct TRI_skiplist_multi_s { // ........................................................................... int (*compareElementElement) (struct TRI_skiplist_multi_s*, void*, void*, int); int (*compareKeyElement) (struct TRI_skiplist_multi_s*, void*, void*, int); + + // ........................................................................... + // Returns true if the element is an exact copy, or if the data which the + // element points to is an exact copy + // ........................................................................... + bool (*equalElementElement) (struct TRI_skiplist_multi_s*, void*, void*); } TRI_skiplist_multi_t; @@ -381,6 +395,7 @@ void TRI_InitSkipListMulti (TRI_skiplist_multi_t*, size_t elementSize, int (*compareElementElement) (TRI_skiplist_multi_t*, void*, void*, int), int (*compareKeyElement) (TRI_skiplist_multi_t*, void*, void*, int), + bool (*equalElementElement) (TRI_skiplist_multi_t*, void*, void*), TRI_skiplist_prob_e, uint32_t); diff --git a/SkipLists/skiplistIndex.c b/SkipLists/skiplistIndex.c index 10c8e83911..d550a27e94 100755 --- a/SkipLists/skiplistIndex.c +++ b/SkipLists/skiplistIndex.c @@ -878,8 +878,8 @@ static int CompareElementElement (struct TRI_skiplist_s* skiplist, void* leftEle // This is where the difference between CompareKeyElement (below) and // CompareElementElement comes into play. Here if the 'keys' are the same, // but the doc ptr is different (which it is since we are here), then - // we return 1 to indicate that the leftElement is bigger than the rightElement - // this has the effect of moving to the next node in the skiplist. + // we return what was requested to be returned: 0,-1 or 1. What is returned + // depends on the purpose of calling this callback. // ............................................................................ return defaultEqual; @@ -1287,19 +1287,19 @@ static int MultiCompareElementElement (TRI_skiplist_multi_t* multiSkiplist, void if (leftElement == NULL && rightElement == NULL) { - return 0; + return TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL; } if (leftElement != NULL && rightElement == NULL) { - return 1; + return TRI_SKIPLIST_COMPARE_STRICTLY_GREATER; } if (leftElement == NULL && rightElement != NULL) { - return -1; + return TRI_SKIPLIST_COMPARE_STRICTLY_LESS; } if (leftElement == rightElement) { - return 0; + return TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL; } if (hLeftElement->numFields != hRightElement->numFields) { @@ -1307,7 +1307,7 @@ static int MultiCompareElementElement (TRI_skiplist_multi_t* multiSkiplist, void } if (hLeftElement->data == hRightElement->data) { - return 0; + return TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL; } @@ -1389,6 +1389,30 @@ static int MultiCompareKeyElement (TRI_skiplist_multi_t* multiSkiplist, void* l } +//////////////////////////////////////////////////////////////////////////////// +/// @brief used to determine the order of two keys +//////////////////////////////////////////////////////////////////////////////// + +static bool MultiEqualElementElement (TRI_skiplist_multi_t* multiSkiplist, void* leftElement, void* rightElement) { + + SkiplistIndexElement* hLeftElement = (SkiplistIndexElement*)(leftElement); + SkiplistIndexElement* hRightElement = (SkiplistIndexElement*)(rightElement); + + if (leftElement == rightElement) { + return true; + } + + /* + printf("%s:%u:%f:%f,%u:%u\n",__FILE__,__LINE__, + *((double*)((hLeftElement->fields)->_data.data)), + *((double*)((hRightElement->fields)->_data.data)), + (uint64_t)(hLeftElement->data), + (uint64_t)(hRightElement->data) + ); + */ + return (hLeftElement->data == hRightElement->data); +} + @@ -1424,6 +1448,7 @@ SkiplistIndex* MultiSkiplistIndex_new() { sizeof(SkiplistIndexElement), MultiCompareElementElement, MultiCompareKeyElement, + MultiEqualElementElement, TRI_SKIPLIST_PROB_HALF, 40); return skiplistIndex; @@ -1435,6 +1460,7 @@ SkiplistIndex* MultiSkiplistIndex_new() { /// @brief adds (inserts) a data element into a multi skiplist //////////////////////////////////////////////////////////////////////////////// + int MultiSkiplistIndex_add(SkiplistIndex* skiplistIndex, SkiplistIndexElement* element) { bool result; result = TRI_InsertElementSkipListMulti(skiplistIndex->skiplist.nonUniqueSkiplist, element, false); diff --git a/UnitTests/RestDocuments/rest_delete-document_spec.rb b/UnitTests/RestDocuments/rest_delete-document_spec.rb new file mode 100644 index 0000000000..b03bf40a0e --- /dev/null +++ b/UnitTests/RestDocuments/rest_delete-document_spec.rb @@ -0,0 +1,28 @@ +require 'rspec' +require './avocadodb.rb' + +describe AvocadoDB do + context "delete a document in a collection" do + +################################################################################ +## error handling +################################################################################ + + context "error handling" do + it "returns an error if document handle is missing" do + cmd = "/document" + doc = AvocadoDB.delete(cmd) + + doc.code.should eq(400) + doc.parsed_response['error'].should eq(true) + doc.parsed_response['errorNum'].should eq(1202) + doc.parsed_response['code'].should eq(400) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + + AvocadoDB.log(:method => :post, :url => cmd, :result => doc, :output => "rest_delete-document-missing-handle") + end + end + + end +end + diff --git a/UnitTests/RestDocuments/rest_read-document_spec.rb b/UnitTests/RestDocuments/rest_read-document_spec.rb index af3a9a84f3..5689ff21b6 100644 --- a/UnitTests/RestDocuments/rest_read-document_spec.rb +++ b/UnitTests/RestDocuments/rest_read-document_spec.rb @@ -125,7 +125,8 @@ describe AvocadoDB do # get document, if-none-match with same rev cmd = "/document/#{did}" - doc = AvocadoDB.get(cmd, :headers => { "if-none-match" => "\"#{rev}\"" }) + hdr = { "if-none-match" => "\"#{rev}\"" } + doc = AvocadoDB.get(cmd, :headers => hdr) doc.code.should eq(304) @@ -134,11 +135,12 @@ describe AvocadoDB do etag.should eq("\"#{rev}\"") - AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "rest_read-document-if-none-match") + AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "rest_read-document-if-none-match") # get document, if-none-match with different rev cmd = "/document/#{did}" - doc = AvocadoDB.get(cmd, :headers => { "if-none-match" => "\"#{rev-1}\"" }) + hdr = { "if-none-match" => "\"#{rev-1}\"" } + doc = AvocadoDB.get(cmd, :headers => hdr) doc.code.should eq(200) doc.headers['content-type'].should eq("application/json; charset=utf-8") @@ -161,11 +163,12 @@ describe AvocadoDB do etag.should eq("\"#{rev}\"") - AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "rest_read-document-if-none-match-other") + AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "rest_read-document-if-none-match-other") # get document, if-match with same rev cmd = "/document/#{did}" - doc = AvocadoDB.get(cmd, :headers => { "if-match" => "\"#{rev}\"" }) + hdr = { "if-match" => "\"#{rev}\"" } + doc = AvocadoDB.get(cmd, :headers => hdr) doc.code.should eq(200) doc.headers['content-type'].should eq("application/json; charset=utf-8") @@ -183,15 +186,17 @@ describe AvocadoDB do etag.should eq("\"#{rev}\"") - AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "rest_read-document-if-match") + AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "rest_read-document-if-match") # get document, if-match with different rev cmd = "/document/#{did}" - doc = AvocadoDB.get(cmd, :headers => { "if-match" => "\"#{rev-1}\"" }) + hdr = { "if-match" => "\"#{rev-1}\"" } + doc = AvocadoDB.get(cmd, :headers => hdr) doc.code.should eq(412) + doc.headers['content-length'].should eq(0) - AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "rest_read-document-if-match-other") + AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "rest_read-document-if-match-other") AvocadoDB.delete(location) end diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index a0b9abc728..7789fec4f0 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -1400,6 +1400,7 @@ static TRI_json_t* ConvertHelper(v8::Handle parameter) { TRI_json_t* result = ConvertHelper(item); if (result) { TRI_PushBack2ListJson(listJson, result); + TRI_Free(result); } } } @@ -1416,6 +1417,7 @@ static TRI_json_t* ConvertHelper(v8::Handle parameter) { TRI_json_t* result = ConvertHelper(item); if (result) { TRI_Insert2ArrayJson(arrayJson, TRI_ObjectToString(key).c_str(), result); + TRI_Free(result); } } } @@ -1544,7 +1546,6 @@ static v8::Handle JS_StatementAql (v8::Arguments const& argv) { parameters = ConvertHelper(argv[1]); } - // TODO: properly free parameters instance = TRI_CreateQueryInstance(template_, parameters); if (!instance) { if (parameters) { @@ -3078,7 +3079,7 @@ static v8::Handle JS_DeleteVocbaseCol (v8::Arguments const& argv) { // inside a write transaction // ............................................................................. - bool ok = collection->destroyLock(collection, did, 0, TRI_DOC_UPDATE_LAST_WRITE); + bool ok = collection->destroyLock(collection, did, 0, 0, TRI_DOC_UPDATE_LAST_WRITE); // ............................................................................. // outside a write transaction @@ -4164,7 +4165,7 @@ static v8::Handle JS_ReplaceVocbaseCol (v8::Arguments const& argv) { // inside a write transaction // ............................................................................. - bool ok = collection->updateLock(collection, shaped, did, 0, TRI_DOC_UPDATE_LAST_WRITE); + bool ok = collection->updateLock(collection, shaped, did, 0, 0, TRI_DOC_UPDATE_LAST_WRITE); // ............................................................................. // outside a write transaction @@ -4348,7 +4349,7 @@ static v8::Handle JS_ReplaceEdgesCol (v8::Arguments const& argv) { // inside a write transaction // ............................................................................. - bool ok = collection->updateLock(collection, shaped, did, 0, TRI_DOC_UPDATE_LAST_WRITE); + bool ok = collection->updateLock(collection, shaped, did, 0, 0, TRI_DOC_UPDATE_LAST_WRITE); // ............................................................................. // outside a write transaction diff --git a/V8Client/shell.cpp b/V8Client/shell.cpp index b594ae89eb..89637b0aeb 100644 --- a/V8Client/shell.cpp +++ b/V8Client/shell.cpp @@ -56,6 +56,7 @@ using namespace triagens::avocado; #include "js/common/bootstrap/js-print.h" #include "js/common/bootstrap/js-modules.h" +#include "js/common/bootstrap/js-errors.h" #include "js/client/js-client.h" // ----------------------------------------------------------------------------- @@ -1055,6 +1056,7 @@ int main (int argc, char* argv[]) { if (StartupPath.empty()) { StartupLoader.defineScript("common/bootstrap/modules.js", JS_common_bootstrap_modules); StartupLoader.defineScript("common/bootstrap/print.js", JS_common_bootstrap_print); + StartupLoader.defineScript("common/bootstrap/errors.js", JS_common_bootstrap_errors); StartupLoader.defineScript("client/client.js", JS_client_client); } else { @@ -1066,6 +1068,7 @@ int main (int argc, char* argv[]) { char const* files[] = { "common/bootstrap/modules.js", "common/bootstrap/print.js", + "common/bootstrap/errors.js", "client/client.js" }; diff --git a/VocBase/document-collection.c b/VocBase/document-collection.c index 9d1e126e6b..4c1de4a886 100644 --- a/VocBase/document-collection.c +++ b/VocBase/document-collection.c @@ -93,11 +93,12 @@ static bool UpdateLock (TRI_doc_collection_t* document, TRI_shaped_json_t const* json, TRI_voc_did_t did, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy) { TRI_doc_mptr_t const* result; document->beginWrite(document); - result = document->update(document, json, did, rid, policy, true); + result = document->update(document, json, did, rid, oldRid, policy, true); return result != NULL; } @@ -110,6 +111,7 @@ static TRI_doc_mptr_t const* UpdateJson (TRI_doc_collection_t* collection, TRI_json_t const* json, TRI_voc_did_t did, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy, bool release) { TRI_shaped_json_t* shaped; @@ -122,7 +124,7 @@ static TRI_doc_mptr_t const* UpdateJson (TRI_doc_collection_t* collection, return false; } - result = collection->update(collection, shaped, did, rid, policy, release); + result = collection->update(collection, shaped, did, rid, oldRid, policy, release); TRI_FreeShapedJson(shaped); @@ -136,11 +138,12 @@ static TRI_doc_mptr_t const* UpdateJson (TRI_doc_collection_t* collection, static bool DestroyLock (TRI_doc_collection_t* document, TRI_voc_did_t did, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy) { bool ok; document->beginWrite(document); - ok = document->destroy(document, did, rid, policy, true); + ok = document->destroy(document, did, rid, oldRid, policy, true); return ok; } diff --git a/VocBase/document-collection.h b/VocBase/document-collection.h index 7890b450cc..84dab19921 100644 --- a/VocBase/document-collection.h +++ b/VocBase/document-collection.h @@ -218,7 +218,7 @@ TRI_doc_collection_info_t; /// of success. Otherwise, @c false is returned and the "TRI_errno()" is /// accordingly. The function will acquire and release a write lock. /// -/// bool destroy (TRI_doc_collection_t*, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e, bool release) +/// bool destroy (TRI_doc_collection_t*, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e, bool release) /// /// Deletes an existing document of the collection and returns @c true in case /// of success. Otherwise, @c false is returned and the "TRI_errno()" is @@ -263,12 +263,12 @@ typedef struct TRI_doc_collection_s { TRI_doc_mptr_t const* (*read) (struct TRI_doc_collection_s*, TRI_voc_did_t); - TRI_doc_mptr_t const* (*update) (struct TRI_doc_collection_s*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e, bool release); - TRI_doc_mptr_t const* (*updateJson) (struct TRI_doc_collection_s*, TRI_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e, bool release); - bool (*updateLock) (struct TRI_doc_collection_s*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e); + TRI_doc_mptr_t const* (*update) (struct TRI_doc_collection_s*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e, bool release); + TRI_doc_mptr_t const* (*updateJson) (struct TRI_doc_collection_s*, TRI_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e, bool release); + bool (*updateLock) (struct TRI_doc_collection_s*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e); - bool (*destroy) (struct TRI_doc_collection_s* collection, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e, bool release); - bool (*destroyLock) (struct TRI_doc_collection_s* collection, TRI_voc_did_t, TRI_voc_rid_t, TRI_doc_update_policy_e); + bool (*destroy) (struct TRI_doc_collection_s* collection, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e, bool release); + bool (*destroyLock) (struct TRI_doc_collection_s* collection, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t*, TRI_doc_update_policy_e); TRI_doc_collection_info_t* (*figures) (struct TRI_doc_collection_s* collection); TRI_voc_size_t (*size) (struct TRI_doc_collection_s* collection); diff --git a/VocBase/query-base.h b/VocBase/query-base.h index bd09f0fbdd..bcf690ea11 100644 --- a/VocBase/query-base.h +++ b/VocBase/query-base.h @@ -36,8 +36,8 @@ #include #include "VocBase/vocbase.h" +#include "VocBase/voc-errors.h" #include "VocBase/query-node.h" -#include "VocBase/query-error.h" #include "QL/parser.h" #include "QL/ast-query.h" diff --git a/VocBase/query-cursor.c b/VocBase/query-cursor.c index e3c504c760..52297cac5f 100644 --- a/VocBase/query-cursor.c +++ b/VocBase/query-cursor.c @@ -28,6 +28,10 @@ #include "VocBase/query-cursor.h" #include "VocBase/query-context.h" +// ----------------------------------------------------------------------------- +// --SECTION-- private functions +// ----------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////// /// @addtogroup VocBase /// @{ @@ -49,6 +53,32 @@ static void RemoveCollectionsQueryCursor (TRI_query_cursor_t* cursor) { cursor->_containers._length = 0; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief frees the data of a cursor +/// +/// This will release any locks on the underlying collection data and might be +/// called before the actual cursor is disposed. +//////////////////////////////////////////////////////////////////////////////// + +static void FreeData (TRI_query_cursor_t* const cursor) { + if (cursor->_deleted) { + return; + } + + cursor->_deleted = true; + + assert(cursor->_functionCode); + TRI_Free(cursor->_functionCode); + + // free result set + if (cursor->_result._selectResult) { + cursor->_result._selectResult->free(cursor->_result._selectResult); + } + + // free select + RemoveCollectionsQueryCursor(cursor); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief returns the next element //////////////////////////////////////////////////////////////////////////////// @@ -61,6 +91,8 @@ static TRI_rc_result_t* NextQueryCursor (TRI_query_cursor_t* const cursor) { return &cursor->_result; } + FreeData(cursor); + return NULL; } @@ -88,27 +120,33 @@ static uint32_t GetBatchSizeQueryCursor (const TRI_query_cursor_t* const cursor) return cursor->_batchSize; } +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// /// @brief frees a cursor //////////////////////////////////////////////////////////////////////////////// void TRI_FreeQueryCursor (TRI_query_cursor_t* cursor) { - assert(cursor->_functionCode); - TRI_Free(cursor->_functionCode); - - // free result set - if (cursor->_result._selectResult) { - cursor->_result._selectResult->free(cursor->_result._selectResult); - } + FreeData(cursor); - // free select - RemoveCollectionsQueryCursor(cursor); TRI_DestroyMutex(&cursor->_lock); TRI_DestroyVectorPointer(&cursor->_containers); TRI_Free(cursor); } + //////////////////////////////////////////////////////////////////////////////// /// @brief create a cursor //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/query-cursor.h b/VocBase/query-cursor.h index 2da20a985e..297aba146c 100644 --- a/VocBase/query-cursor.h +++ b/VocBase/query-cursor.h @@ -37,6 +37,10 @@ extern "C" { #endif +// ----------------------------------------------------------------------------- +// --SECTION-- public types +// ----------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////// /// @addtogroup VocBase /// @{ @@ -67,6 +71,18 @@ typedef struct TRI_query_cursor_s { } TRI_query_cursor_t; +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief frees a cursor diff --git a/VocBase/query-error.c b/VocBase/query-error.c deleted file mode 100644 index 3ef9e8f1b1..0000000000 --- a/VocBase/query-error.c +++ /dev/null @@ -1,79 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief query errors -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 2010-2012 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 Jan Steemann -/// @author Copyright 2012, triagens GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -#include "VocBase/query-error.h" - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup AvocadoErrors -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief initialize query error definitions -//////////////////////////////////////////////////////////////////////////////// - -void TRI_InitialiseQueryErrors (void) { - REG_ERROR(OOM, "out of memory"); - REG_ERROR(KILLED, "query killed"); - - REG_ERROR(PARSE, "parse error: %s"); - REG_ERROR(EMPTY, "query is empty"); - - REG_ERROR(NUMBER_OUT_OF_RANGE, "number '%s' is out of range"); - REG_ERROR(LIMIT_VALUE_OUT_OF_RANGE, "limit value '%s' is out of range"); - - REG_ERROR(TOO_MANY_JOINS, "too many joins"); - - REG_ERROR(COLLECTION_NAME_INVALID, "collection name '%s' is invalid"); - REG_ERROR(COLLECTION_ALIAS_INVALID, "collection alias '%s' is invalid"); - REG_ERROR(COLLECTION_ALIAS_REDECLARED, "collection alias '%s' is declared multiple times in the same query"); - REG_ERROR(COLLECTION_ALIAS_UNDECLARED, "collection alias '%s' is used but was not declared in the from clause"); - - REG_ERROR(COLLECTION_NOT_FOUND, "unable to open collection '%s'"); - - REG_ERROR(GEO_RESTRICTION_INVALID, "geo restriction for alias '%s' is invalid"); - REG_ERROR(GEO_INDEX_MISSING, "no suitable geo index found for geo restriction on '%s'"); - - REG_ERROR(BIND_PARAMETER_MISSING, "no value specified for bind parameter '%s'"); - REG_ERROR(BIND_PARAMETER_REDECLARED, "value for bind parameter '%s' is declared multiple times"); - REG_ERROR(BIND_PARAMETER_UNDECLARED, "bind parameter '%s' was not declared in the query"); - REG_ERROR(BIND_PARAMETER_VALUE_INVALID, "invalid value for bind parameter '%s'"); - REG_ERROR(BIND_PARAMETER_NUMBER_OUT_OF_RANGE, "bind parameter number '%s' out of range"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" -// End: diff --git a/VocBase/query-error.h b/VocBase/query-error.h deleted file mode 100644 index ded9e3a2f4..0000000000 --- a/VocBase/query-error.h +++ /dev/null @@ -1,249 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief query errors -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 2010-2012 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 Jan Steemann -/// @author Copyright 2012, triagens GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -#ifndef DURHAM_STORAGE_VOCBASE_QUERY_ERROR_H -#define DURHAM_STORAGE_VOCBASE_QUERY_ERROR_H 1 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup AvocadoErrors -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- definitions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief error numbers for specific errors during query parsing and execution -/// -/// Note that the error numbers defined here must not conflict with error -/// numbers defined for other parts of the program (e.g. in VocBase/vocbase.h) -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BASE (1500) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1500: Out of memory. -/// -/// Will be raised during query execution when a memory allocation request can -/// not be satisfied. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_OOM (1500) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1501: Query was killed by administrator. -/// -/// Will be raised when a running query is killed by an explicit admin command. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_KILLED (1501) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1510: Parse error. -/// -/// Will be raised when query is parsed and is found to be syntactially invalid. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_PARSE (1510) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1511: Query is emtpy / no command specified. -/// -/// Will be raised when an empty query is specified. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_EMPTY (1511) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1520: Specified numeric value is out of range. -/// -/// Will be raised when a numeric value inside a query is out of the allowed -/// value range. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE (1520) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1521: Specified limit value is out of range. -/// -/// Will be raised when a limit value in the query is outside the allowed range -/// (e. g. when passing a negative skip value) -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE (1521) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1540: Too many joins. -/// -/// Will be raised when the number of joins in a query is beyond the allowed -/// value. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_TOO_MANY_JOINS (1540) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1550: Invalid name for collection. -/// -/// Will be raised when an invalid collection name is used in the from clause -/// of a query. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_COLLECTION_NAME_INVALID (1550) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1551: Invalid alias for collection. -/// -/// Will be raised when an invalid alias name is used for a collection. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_COLLECTION_ALIAS_INVALID (1551) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1552: Redeclaration of alias within query. -/// -/// Will be raised when the same alias name is declared multiple times in the -/// same query's from clause. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_COLLECTION_ALIAS_REDECLARED (1552) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1553: Usage of undeclared alias in query. -/// -/// Will be raised when an alias not declared in the from clause is used in the -/// query. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_COLLECTION_ALIAS_UNDECLARED (1553) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1560: Collection not found. -/// -/// Will be raised when one of the collections referenced in the query was not -/// found. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_COLLECTION_NOT_FOUND (1560) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1570: Invalid geo restriction specification. -/// -/// Will be raised when a specified geo restriction is invalid. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_GEO_RESTRICTION_INVALID (1570) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1571: No suitable geo index found to resolve query. -/// -/// Will be raised when a geo restriction was specified but no suitable geo -/// index is found to resolve it. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_GEO_INDEX_MISSING (1571) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1590: No value specified for declared bind parameter. -/// -/// Will be raised when a bind parameter was declared in the query but the -/// query is being executed with no value for that parameter. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BIND_PARAMETER_MISSING (1590) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1591: Redeclaration of same bind parameter value. -/// -/// Will be raised when a value gets specified multiple times for the same bind -/// parameter. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BIND_PARAMETER_REDECLARED (1591) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1592: Value specified for undeclared bind parameter. -/// -/// Will be raised when a value gets specified for an undeclared bind parameter. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BIND_PARAMETER_UNDECLARED (1592) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1593: Invalid value for bind parameter. -/// -/// Will be raised when an invalid value is specified for one of the bind -/// parameters. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID (1593) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1594: Bind parameter number is out of range. -/// -/// Will be specified when the numeric index for a bind parameter of type -/// @LIT{\@n} is out of the allowed range. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE (1594) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief helper macro to define an error string -//////////////////////////////////////////////////////////////////////////////// - -#define REG_ERROR(id, label) TRI_set_errno_string(TRI_ERROR_QUERY_ ## id, label); - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief initialize query error definitions -//////////////////////////////////////////////////////////////////////////////// - -void TRI_InitialiseQueryErrors (void); - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif - -#endif - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" -// End: diff --git a/VocBase/query-parse.h b/VocBase/query-parse.h index 8d8e63ccbd..900dd32d19 100644 --- a/VocBase/query-parse.h +++ b/VocBase/query-parse.h @@ -28,8 +28,8 @@ #ifndef TRIAGENS_DURHAM_VOC_BASE_QUERY_PARSE_H #define TRIAGENS_DURHAM_VOC_BASE_QUERY_PARSE_H 1 +#include "VocBase/voc-errors.h" #include "VocBase/query-base.h" -#include "VocBase/query-error.h" #include "VocBase/query-memory.h" #include "QL/optimize.h" diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c index 6c8c2e8daa..e6d7051448 100644 --- a/VocBase/simple-collection.c +++ b/VocBase/simple-collection.c @@ -360,6 +360,7 @@ static TRI_doc_mptr_t const* UpdateDocument (TRI_sim_collection_t* collection, void const* body, TRI_voc_size_t bodySize, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy, TRI_df_marker_t** result, bool release) { @@ -368,6 +369,10 @@ static TRI_doc_mptr_t const* UpdateDocument (TRI_sim_collection_t* collection, bool ok; // check the revision + if (oldRid != NULL) { + *oldRid = header->_rid; + } + switch (policy) { case TRI_DOC_UPDATE_ERROR: if (rid != 0) { @@ -482,6 +487,7 @@ static TRI_doc_mptr_t const* UpdateDocument (TRI_sim_collection_t* collection, static bool DeleteDocument (TRI_sim_collection_t* collection, TRI_doc_deletion_marker_t* marker, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy, bool release) { TRI_datafile_t* journal; @@ -504,6 +510,10 @@ static bool DeleteDocument (TRI_sim_collection_t* collection, } // check the revision + if (oldRid != NULL) { + *oldRid = header->_rid; + } + switch (policy) { case TRI_DOC_UPDATE_ERROR: if (rid != 0) { @@ -800,6 +810,7 @@ static TRI_doc_mptr_t const* UpdateShapedJson (TRI_doc_collection_t* document, TRI_shaped_json_t const* json, TRI_voc_did_t did, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy, bool release) { TRI_df_marker_t const* original; @@ -838,6 +849,7 @@ static TRI_doc_mptr_t const* UpdateShapedJson (TRI_doc_collection_t* document, &marker, sizeof(marker), json->_data.data, json->_data.length, rid, + oldRid, policy, &result, release); @@ -870,6 +882,7 @@ static TRI_doc_mptr_t const* UpdateShapedJson (TRI_doc_collection_t* document, &marker.base, sizeof(marker), json->_data.data, json->_data.length, rid, + oldRid, policy, &result, release); @@ -889,6 +902,7 @@ static TRI_doc_mptr_t const* UpdateShapedJson (TRI_doc_collection_t* document, static bool DeleteShapedJson (TRI_doc_collection_t* document, TRI_voc_did_t did, TRI_voc_rid_t rid, + TRI_voc_rid_t* oldRid, TRI_doc_update_policy_e policy, bool release) { TRI_sim_collection_t* collection; @@ -904,7 +918,7 @@ static bool DeleteShapedJson (TRI_doc_collection_t* document, marker._did = did; marker._sid = 0; - return DeleteDocument(collection, &marker, rid, policy, release); + return DeleteDocument(collection, &marker, rid, oldRid, policy, release); } //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/voc-error.h b/VocBase/voc-error.h deleted file mode 100644 index 663c698b20..0000000000 --- a/VocBase/voc-error.h +++ /dev/null @@ -1,289 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief vocbase error codes -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 2010-2012 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 Dr. Frank Celler -/// @author Jan Steemann -/// @author Copyright 2012, triagens GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -#ifndef TRIAGENS_DURHAM_VOC_VOCBASE_VOC_ERROR_H -#define TRIAGENS_DURHAM_VOC_VOCBASE_VOC_ERROR_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -// ----------------------------------------------------------------------------- -// --SECTION-- public constants -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup AvocadoErrors -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief error codes -/// -/// If you add a new error code, you must also add the description in @ref -/// TRI_InitialiseVocBase. -/// -/// Please note that the error numbers defined here must not conflict with error -/// numbers defined for other parts of the program (e.g. in -/// VocBase/query-error.h) -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_BEGIN (1000) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1000: Illegal state. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_ILLEGAL_STATE (1000) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1001: Shaper failed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_SHAPER_FAILED (1001) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1002: Corrupted datafile. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_CORRUPTED_DATAFILE (1002) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1003: mmap failed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_MMAP_FAILED (1003) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1004: msync failed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_MSYNC_FAILED (1004) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1005: No journal. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_NO_JOURNAL (1005) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1006: Datafile sealed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_DATAFILE_SEALED (1006) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1007: Corrupted collection. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_CORRUPTED_COLLECTION (1007) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1008: Unknown type. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_UNKNOWN_TYPE (1008) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1009: Illegal parameter. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_ILLEGAL_PARAMETER (1009) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1010: Index exists. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_INDEX_EXISTS (1010) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1011: Conflict. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_CONFLICT (1011) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1100: Wrong path. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_WRONG_PATH (1100) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1101: Cannot rename. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_CANNOT_RENAME (1101) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1102: Write failed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_WRITE_FAILED (1102) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1103: Read only. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_READ_ONLY (1103) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1104: Datafile full. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_DATAFILE_FULL (1104) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1105: Filesystem full. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_FILESYSTEM_FULL (1105) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1106: Read failed. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_READ_FAILED (1106) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1107: File not found. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_FILE_NOT_FOUND (1107) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1108: File not accessible. -/// -/// TODO -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_FILE_NOT_ACCESSIBLE (1108) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1200: Document not found. -/// -/// Will be raised when a document with a given identifier or handle is unknown. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_DOCUMENT_NOT_FOUND (1200) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1201: Collection not found. -/// -/// Will be raised when a collection with a given identifier or name is unknown. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_COLLECTION_NOT_FOUND (1201) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1202: Parameter collection not found. -/// -/// Will be raised when the collection parameter is missing. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_COLLECTION_PARAMETER_MISSING (1202) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1203: Document altered. -/// -/// Will be raised when a document has been altered and a change would -/// result in a conflict. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_DOCUMENT_ALTERED (1203) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1203: Illegal document handle. -/// -/// Will be raised when a document handle is corrupt. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_DOCUMENT_HANDLE_BAD (1204) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1205: Collection already exists. -/// -/// Will be raised when a collection with a given identifier or name already -/// exists. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_VOC_ERROR_COLLECTION_EXISTS (1205) - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif - -#endif - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" -// End: diff --git a/VocBase/voc-errors.c b/VocBase/voc-errors.c new file mode 100644 index 0000000000..e799dc6815 --- /dev/null +++ b/VocBase/voc-errors.c @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief auto-generated file generated from errors.dat +//////////////////////////////////////////////////////////////////////////////// + +#include +#include "VocBase/voc-errors.h" + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocError +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitialiseAvocadoErrors (void) { + REG_ERROR(VOC_ERROR_ILLEGAL_STATE, "illegal state"); + REG_ERROR(VOC_ERROR_SHAPER_FAILED, "illegal shaper"); + REG_ERROR(VOC_ERROR_CORRUPTED_DATAFILE, "corrupted datafile"); + REG_ERROR(VOC_ERROR_MMAP_FAILED, "mmap failed"); + REG_ERROR(VOC_ERROR_MSYNC_FAILED, "msync failed"); + REG_ERROR(VOC_ERROR_NO_JOURNAL, "no journal"); + REG_ERROR(VOC_ERROR_DATAFILE_SEALED, "datafile sealed"); + REG_ERROR(VOC_ERROR_CORRUPTED_COLLECTION, "corrupted collection"); + REG_ERROR(VOC_ERROR_UNKNOWN_TYPE, "unknown type"); + REG_ERROR(VOC_ERROR_ILLEGAL_PARAMETER, "illegal parameter"); + REG_ERROR(VOC_ERROR_INDEX_EXISTS, "index exists"); + REG_ERROR(VOC_ERROR_CONFLICT, "conflict"); + REG_ERROR(VOC_ERROR_WRONG_PATH, "wrong path"); + REG_ERROR(VOC_ERROR_CANNOT_RENAME, "cannot rename"); + REG_ERROR(VOC_ERROR_WRITE_FAILED, "write failed"); + REG_ERROR(VOC_ERROR_READ_ONLY, "ready only"); + REG_ERROR(VOC_ERROR_DATAFILE_FULL, "datafile full"); + REG_ERROR(VOC_ERROR_FILESYSTEM_FULL, "filesystem full"); + REG_ERROR(VOC_ERROR_READ_FAILED, "read failed"); + REG_ERROR(VOC_ERROR_FILE_NOT_FOUND, "file not found"); + REG_ERROR(VOC_ERROR_FILE_NOT_ACCESSIBLE, "file not accessible"); + REG_ERROR(VOC_ERROR_DOCUMENT_NOT_FOUND, "document not found"); + REG_ERROR(ERROR_QUERY_OOM, "out of memory"); + REG_ERROR(ERROR_QUERY_KILLED, "query killed"); + REG_ERROR(ERROR_QUERY_PARSE, "parse error: %s"); + REG_ERROR(ERROR_QUERY_EMPTY, "query is empty"); + REG_ERROR(ERROR_QUERY_SPECIFICATION_INVALID, "query specification invalid"); + REG_ERROR(ERROR_QUERY_NUMBER_OUT_OF_RANGE, "number '%s' is out of range"); + REG_ERROR(ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE, "limit value '%s' is out of range"); + REG_ERROR(ERROR_QUERY_TOO_MANY_JOINS, "too many joins."); + REG_ERROR(ERROR_QUERY_COLLECTION_NAME_INVALID, "collection name '%s' is invalid"); + REG_ERROR(ERROR_QUERY_COLLECTION_ALIAS_INVALID, "collection alias '%s' is invalid"); + REG_ERROR(ERROR_QUERY_COLLECTION_ALIAS_REDECLARED, "collection alias '%s' is declared multiple times in the same query"); + REG_ERROR(ERROR_QUERY_COLLECTION_ALIAS_UNDECLARED, "collection alias '%s' is used but was not declared in the from clause"); + REG_ERROR(ERROR_QUERY_COLLECTION_NOT_FOUND, "unable to open collection '%s'"); + REG_ERROR(ERROR_QUERY_GEO_RESTRICTION_INVALID, "geo restriction for alias '%s' is invalid"); + REG_ERROR(ERROR_QUERY_GEO_INDEX_MISSING, "no suitable geo index found for geo restriction on '%s'"); + REG_ERROR(ERROR_QUERY_BIND_PARAMETER_MISSING, "no value specified for declared bind parameter '%s'"); + REG_ERROR(ERROR_QUERY_BIND_PARAMETER_REDECLARED, "value for bind parameter '%s' is declared multiple times"); + REG_ERROR(ERROR_QUERY_BIND_PARAMETER_UNDECLARED, "bind parameter '%s' was not declared in the query"); + REG_ERROR(ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID, "invalid value for bind parameter '%s'"); + REG_ERROR(ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE, "bind parameter number '%s' out of range"); + REG_ERROR(ERROR_CURSOR_NOT_FOUND, "cursor not found"); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + diff --git a/VocBase/voc-errors.h b/VocBase/voc-errors.h new file mode 100644 index 0000000000..95a83b929e --- /dev/null +++ b/VocBase/voc-errors.h @@ -0,0 +1,592 @@ + +#ifndef TRIAGENS_DURHAM_VOC_BASE_ERRORS_H +#define TRIAGENS_DURHAM_VOC_BASE_ERRORS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// @page AvocadoErrors Error codes and meanings +/// +/// The following errors might be raised when running AvocadoDB: +/// +/// - 1000: @CODE{illegal state} +/// TODO +/// - 1001: @CODE{illegal shaper} +/// TODO +/// - 1002: @CODE{corrupted datafile} +/// TODO +/// - 1003: @CODE{mmap failed} +/// TODO +/// - 1004: @CODE{msync failed} +/// TODO +/// - 1005: @CODE{no journal} +/// TODO +/// - 1006: @CODE{datafile sealed} +/// TODO +/// - 1007: @CODE{corrupted collection} +/// TODO +/// - 1008: @CODE{unknown type} +/// TODO +/// - 1009: @CODE{illegal parameter} +/// TODO +/// - 1010: @CODE{index exists} +/// TODO +/// - 1011: @CODE{conflict} +/// TODO +/// - 1100: @CODE{wrong path} +/// TODO +/// - 1101: @CODE{cannot rename} +/// TODO +/// - 1102: @CODE{write failed} +/// TODO +/// - 1103: @CODE{ready only} +/// TODO +/// - 1104: @CODE{datafile full} +/// TODO +/// - 1105: @CODE{filesystem full} +/// TODO +/// - 1106: @CODE{read failed} +/// TODO +/// - 1107: @CODE{file not found} +/// TODO +/// - 1108: @CODE{file not accessible} +/// TODO +/// - 1200: @CODE{document not found} +/// TODO +/// - 1500: @CODE{out of memory} +/// Will be raised during query execution when a memory allocation request +/// can not be satisfied. +/// - 1501: @CODE{query killed} +/// Will be raised when a running query is killed by an explicit admin +/// command. +/// - 1510: @CODE{parse error: \%s} +/// Will be raised when query is parsed and is found to be syntactially +/// invalid. +/// - 1511: @CODE{query is empty} +/// Will be raised when an empty query is specified. +/// - 1512: @CODE{query specification invalid} +/// Will be raised when a query is sent to the server with an incomplete or +/// invalid query specification structure. +/// - 1520: @CODE{number '\%s' is out of range} +/// Will be raised when a numeric value inside a query is out of the allowed +/// value range. +/// - 1521: @CODE{limit value '\%s' is out of range} +/// Will be raised when a limit value in the query is outside the allowed +/// range (e. g. when passing a negative skip value). +/// - 1540: @CODE{too many joins.} +/// Will be raised when the number of joins in a query is beyond the allowed +/// value. +/// - 1550: @CODE{collection name '\%s' is invalid} +/// Will be raised when an invalid collection name is used in the from clause +/// of a query. +/// - 1551: @CODE{collection alias '\%s' is invalid} +/// Will be raised when an invalid alias name is used for a collection. +/// - 1552: @CODE{collection alias '\%s' is declared multiple times in the same query} +/// Will be raised when the same alias name is declared multiple times in the +/// same query's from clause. +/// - 1553: @CODE{collection alias '\%s' is used but was not declared in the from clause} +/// Will be raised when an alias not declared in the from clause is used in +/// the query. +/// - 1560: @CODE{unable to open collection '\%s'} +/// Will be raised when one of the collections referenced in the query was +/// not found. +/// - 1570: @CODE{geo restriction for alias '\%s' is invalid} +/// Will be raised when a specified geo restriction is invalid. +/// - 1571: @CODE{no suitable geo index found for geo restriction on '\%s'} +/// Will be raised when a geo restriction was specified but no suitable geo +/// index is found to resolve it. +/// - 1590: @CODE{no value specified for declared bind parameter '\%s'} +/// Will be raised when a bind parameter was declared in the query but the +/// query is being executed with no value for that parameter. +/// - 1591: @CODE{value for bind parameter '\%s' is declared multiple times} +/// Will be raised when a value gets specified multiple times for the same +/// bind parameter. +/// - 1592: @CODE{bind parameter '\%s' was not declared in the query} +/// Will be raised when a value gets specified for an undeclared bind +/// parameter. +/// - 1593: @CODE{invalid value for bind parameter '\%s'} +/// Will be raised when an invalid value is specified for one of the bind +/// parameters. +/// - 1594: @CODE{bind parameter number '\%s' out of range} +/// Will be specified when the numeric index for a bind parameter of type @n +/// is out of the allowed range. +/// - 1600: @CODE{cursor not found} +/// Will be raised when a cursor is requested via its id but a cursor with +/// that id cannot be found. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocError +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief helper macro to define an error string +//////////////////////////////////////////////////////////////////////////////// + +#define REG_ERROR(id, label) TRI_set_errno_string(TRI_ ## id, label); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief register all errors for AvocadoDB +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitialiseAvocadoErrors (void); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1000: VOC_ERROR_ILLEGAL_STATE +/// +/// illegal state +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_ILLEGAL_STATE (1000) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1001: VOC_ERROR_SHAPER_FAILED +/// +/// illegal shaper +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_SHAPER_FAILED (1001) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1002: VOC_ERROR_CORRUPTED_DATAFILE +/// +/// corrupted datafile +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_CORRUPTED_DATAFILE (1002) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1003: VOC_ERROR_MMAP_FAILED +/// +/// mmap failed +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_MMAP_FAILED (1003) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1004: VOC_ERROR_MSYNC_FAILED +/// +/// msync failed +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_MSYNC_FAILED (1004) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1005: VOC_ERROR_NO_JOURNAL +/// +/// no journal +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_NO_JOURNAL (1005) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1006: VOC_ERROR_DATAFILE_SEALED +/// +/// datafile sealed +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_DATAFILE_SEALED (1006) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1007: VOC_ERROR_CORRUPTED_COLLECTION +/// +/// corrupted collection +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_CORRUPTED_COLLECTION (1007) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1008: VOC_ERROR_UNKNOWN_TYPE +/// +/// unknown type +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_UNKNOWN_TYPE (1008) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1009: VOC_ERROR_ILLEGAL_PARAMETER +/// +/// illegal parameter +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_ILLEGAL_PARAMETER (1009) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1010: VOC_ERROR_INDEX_EXISTS +/// +/// index exists +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_INDEX_EXISTS (1010) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1011: VOC_ERROR_CONFLICT +/// +/// conflict +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_CONFLICT (1011) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1100: VOC_ERROR_WRONG_PATH +/// +/// wrong path +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_WRONG_PATH (1100) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1101: VOC_ERROR_CANNOT_RENAME +/// +/// cannot rename +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_CANNOT_RENAME (1101) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1102: VOC_ERROR_WRITE_FAILED +/// +/// write failed +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_WRITE_FAILED (1102) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1103: VOC_ERROR_READ_ONLY +/// +/// ready only +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_READ_ONLY (1103) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1104: VOC_ERROR_DATAFILE_FULL +/// +/// datafile full +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_DATAFILE_FULL (1104) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1105: VOC_ERROR_FILESYSTEM_FULL +/// +/// filesystem full +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_FILESYSTEM_FULL (1105) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1106: VOC_ERROR_READ_FAILED +/// +/// read failed +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_READ_FAILED (1106) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1107: VOC_ERROR_FILE_NOT_FOUND +/// +/// file not found +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_FILE_NOT_FOUND (1107) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1108: VOC_ERROR_FILE_NOT_ACCESSIBLE +/// +/// file not accessible +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_FILE_NOT_ACCESSIBLE (1108) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1200: VOC_ERROR_DOCUMENT_NOT_FOUND +/// +/// document not found +/// +/// TODO +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_VOC_ERROR_DOCUMENT_NOT_FOUND (1200) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1500: ERROR_QUERY_OOM +/// +/// out of memory +/// +/// Will be raised during query execution when a memory allocation request can +/// not be satisfied. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_OOM (1500) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1501: ERROR_QUERY_KILLED +/// +/// query killed +/// +/// Will be raised when a running query is killed by an explicit admin command. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_KILLED (1501) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1510: ERROR_QUERY_PARSE +/// +/// parse error: %s +/// +/// Will be raised when query is parsed and is found to be syntactially invalid. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_PARSE (1510) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1511: ERROR_QUERY_EMPTY +/// +/// query is empty +/// +/// Will be raised when an empty query is specified. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_EMPTY (1511) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1512: ERROR_QUERY_SPECIFICATION_INVALID +/// +/// query specification invalid +/// +/// Will be raised when a query is sent to the server with an incomplete or +/// invalid query specification structure. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_SPECIFICATION_INVALID (1512) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1520: ERROR_QUERY_NUMBER_OUT_OF_RANGE +/// +/// number '%s' is out of range +/// +/// Will be raised when a numeric value inside a query is out of the allowed +/// value range. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE (1520) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1521: ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE +/// +/// limit value '%s' is out of range +/// +/// Will be raised when a limit value in the query is outside the allowed range +/// (e. g. when passing a negative skip value). +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE (1521) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1540: ERROR_QUERY_TOO_MANY_JOINS +/// +/// too many joins. +/// +/// Will be raised when the number of joins in a query is beyond the allowed +/// value. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_TOO_MANY_JOINS (1540) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1550: ERROR_QUERY_COLLECTION_NAME_INVALID +/// +/// collection name '%s' is invalid +/// +/// Will be raised when an invalid collection name is used in the from clause +/// of a query. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_COLLECTION_NAME_INVALID (1550) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1551: ERROR_QUERY_COLLECTION_ALIAS_INVALID +/// +/// collection alias '%s' is invalid +/// +/// Will be raised when an invalid alias name is used for a collection. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_COLLECTION_ALIAS_INVALID (1551) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1552: ERROR_QUERY_COLLECTION_ALIAS_REDECLARED +/// +/// collection alias '%s' is declared multiple times in the same query +/// +/// Will be raised when the same alias name is declared multiple times in the +/// same query's from clause. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_COLLECTION_ALIAS_REDECLARED (1552) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1553: ERROR_QUERY_COLLECTION_ALIAS_UNDECLARED +/// +/// collection alias '%s' is used but was not declared in the from clause +/// +/// Will be raised when an alias not declared in the from clause is used in the +/// query. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_COLLECTION_ALIAS_UNDECLARED (1553) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1560: ERROR_QUERY_COLLECTION_NOT_FOUND +/// +/// unable to open collection '%s' +/// +/// Will be raised when one of the collections referenced in the query was not +/// found. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_COLLECTION_NOT_FOUND (1560) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1570: ERROR_QUERY_GEO_RESTRICTION_INVALID +/// +/// geo restriction for alias '%s' is invalid +/// +/// Will be raised when a specified geo restriction is invalid. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_GEO_RESTRICTION_INVALID (1570) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1571: ERROR_QUERY_GEO_INDEX_MISSING +/// +/// no suitable geo index found for geo restriction on '%s' +/// +/// Will be raised when a geo restriction was specified but no suitable geo +/// index is found to resolve it. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_GEO_INDEX_MISSING (1571) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1590: ERROR_QUERY_BIND_PARAMETER_MISSING +/// +/// no value specified for declared bind parameter '%s' +/// +/// Will be raised when a bind parameter was declared in the query but the +/// query is being executed with no value for that parameter. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_BIND_PARAMETER_MISSING (1590) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1591: ERROR_QUERY_BIND_PARAMETER_REDECLARED +/// +/// value for bind parameter '%s' is declared multiple times +/// +/// Will be raised when a value gets specified multiple times for the same bind +/// parameter. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_BIND_PARAMETER_REDECLARED (1591) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1592: ERROR_QUERY_BIND_PARAMETER_UNDECLARED +/// +/// bind parameter '%s' was not declared in the query +/// +/// Will be raised when a value gets specified for an undeclared bind parameter. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_BIND_PARAMETER_UNDECLARED (1592) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1593: ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID +/// +/// invalid value for bind parameter '%s' +/// +/// Will be raised when an invalid value is specified for one of the bind +/// parameters. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID (1593) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1594: ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE +/// +/// bind parameter number '%s' out of range +/// +/// Will be specified when the numeric index for a bind parameter of type @n is +/// out of the allowed range. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE (1594) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1600: ERROR_CURSOR_NOT_FOUND +/// +/// cursor not found +/// +/// Will be raised when a cursor is requested via its id but a cursor with that +/// id cannot be found. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_CURSOR_NOT_FOUND (1600) + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/VocBase/vocbase.c b/VocBase/vocbase.c index cc833c17ff..d2f19f7af6 100644 --- a/VocBase/vocbase.c +++ b/VocBase/vocbase.c @@ -890,44 +890,7 @@ void TRI_InitialiseVocBase () { TRI_InitSpin(&TickLock); - // general errors - TRI_set_errno_string(TRI_VOC_ERROR_ILLEGAL_STATE, "illegal state"); - TRI_set_errno_string(TRI_VOC_ERROR_SHAPER_FAILED, "illegal shaper"); - TRI_set_errno_string(TRI_VOC_ERROR_CORRUPTED_DATAFILE, "corrupted datafile"); - TRI_set_errno_string(TRI_VOC_ERROR_MMAP_FAILED, "mmap failed"); - TRI_set_errno_string(TRI_VOC_ERROR_MSYNC_FAILED, "msync failed"); - TRI_set_errno_string(TRI_VOC_ERROR_NO_JOURNAL, "no journal"); - TRI_set_errno_string(TRI_VOC_ERROR_DATAFILE_SEALED, "datafile sealed"); - TRI_set_errno_string(TRI_VOC_ERROR_CORRUPTED_COLLECTION, "corrupted collection"); - TRI_set_errno_string(TRI_VOC_ERROR_UNKNOWN_TYPE, "unknown type"); - TRI_set_errno_string(TRI_VOC_ERROR_ILLEGAL_PARAMETER, "illegal paramater"); - TRI_set_errno_string(TRI_VOC_ERROR_INDEX_EXISTS, "index exists"); - TRI_set_errno_string(TRI_VOC_ERROR_CONFLICT, "conflict"); - - // open errors - TRI_set_errno_string(TRI_VOC_ERROR_WRONG_PATH, "wrong path"); - - // close errors - TRI_set_errno_string(TRI_VOC_ERROR_CANNOT_RENAME, "cannot rename"); - - // write errors - TRI_set_errno_string(TRI_VOC_ERROR_WRITE_FAILED, "write failed"); - TRI_set_errno_string(TRI_VOC_ERROR_READ_ONLY, "read only"); - TRI_set_errno_string(TRI_VOC_ERROR_DATAFILE_FULL, "datafile full"); - TRI_set_errno_string(TRI_VOC_ERROR_FILESYSTEM_FULL, "filesystem full"); - - // read errors - TRI_set_errno_string(TRI_VOC_ERROR_READ_FAILED, "read failed"); - TRI_set_errno_string(TRI_VOC_ERROR_FILE_NOT_FOUND, "file not found"); - TRI_set_errno_string(TRI_VOC_ERROR_FILE_NOT_ACCESSIBLE, "file not accessible"); - - // api errors - TRI_set_errno_string(TRI_VOC_ERROR_COLLECTION_EXISTS, "collection already exists"); - TRI_set_errno_string(TRI_VOC_ERROR_COLLECTION_NOT_FOUND, "collection not found"); - TRI_set_errno_string(TRI_VOC_ERROR_COLLECTION_PARAMETER_MISSING, "parameter is missing"); - TRI_set_errno_string(TRI_VOC_ERROR_DOCUMENT_ALTERED, "document has been altered"); - TRI_set_errno_string(TRI_VOC_ERROR_DOCUMENT_HANDLE_BAD, "illegal or corrupted document handle"); - TRI_set_errno_string(TRI_VOC_ERROR_DOCUMENT_NOT_FOUND, "document not found"); + TRI_InitialiseAvocadoErrors(); #ifdef TRI_READLINE_VERSION LOG_TRACE("%s", "$Revision: READLINE " TRI_READLINE_VERSION " $"); diff --git a/VocBase/vocbase.h b/VocBase/vocbase.h index 2b339d8df9..3af90861b3 100644 --- a/VocBase/vocbase.h +++ b/VocBase/vocbase.h @@ -35,7 +35,7 @@ #include #include -#include "VocBase/voc-error.h" +#include "VocBase/voc-errors.h" #ifdef __cplusplus extern "C" { diff --git a/js/actions/system/aql-cursor.js b/js/actions/system/aql-cursor.js index 29ca99c706..8a29a1c36c 100644 --- a/js/actions/system/aql-cursor.js +++ b/js/actions/system/aql-cursor.js @@ -84,7 +84,7 @@ function getCursorResult(cursor) { function postCursor(req, res) { if (req.suffix.length != 0) { - actions.actionResultError (req, res, 400, actions.cursorNotModified, "Invalid query data"); + actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request"); return; } @@ -92,7 +92,7 @@ function postCursor(req, res) { var json = JSON.parse(req.requestBody); if (!json || !(json instanceof Object)) { - actions.actionResultError (req, res, 400, actions.cursorNotModified, "Invalid query data"); + actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid"); return; } @@ -104,11 +104,12 @@ function postCursor(req, res) { (json.batchSize != undefined ? json.batchSize : 1000)); } else { - actions.actionResultError (req, res, 400, actions.cursorNotModified, "Invalid query data"); + actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid"); return; } if (cursor instanceof AvocadoQueryError) { + // error occurred actions.actionResultError (req, res, 404, cursor.code, cursor.message); return; } @@ -119,7 +120,7 @@ function postCursor(req, res) { actions.actionResultOK(req, res, 201, result); } catch (e) { - actions.actionResultError (req, res, 404, actions.cursorNotModified, "Cursor not created"); + actions.actionResultError (req, res, 404, actions.errorJavascriptException, "Javascript exception"); } } @@ -129,7 +130,7 @@ function postCursor(req, res) { function putCursor(req, res) { if (req.suffix.length != 1) { - actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found"); + actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request"); return; } @@ -144,7 +145,7 @@ function putCursor(req, res) { actions.actionResultOK(req, res, 200, getCursorResult(cursor)); } catch (e) { - actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found"); + actions.actionResultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found"); } } @@ -154,7 +155,7 @@ function putCursor(req, res) { function deleteCursor(req, res) { if (req.suffix.length != 1) { - actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found"); + actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request"); return; } @@ -169,7 +170,7 @@ function deleteCursor(req, res) { actions.actionResultOK(req, res, 202, { "_id" : cursorId }); } catch (e) { - actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found"); + actions.actionResultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found"); } } diff --git a/js/actions/system/aql-query.js b/js/actions/system/aql-query.js index 402e8f6726..8d0a731004 100644 --- a/js/actions/system/aql-query.js +++ b/js/actions/system/aql-query.js @@ -42,7 +42,7 @@ var actions = require("actions"); function postQuery(req, res) { if (req.suffix.length != 0) { - actions.actionResultError (req, res, 400, actions.queryNotModified, "Invalid query data"); + actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request"); return; } @@ -50,7 +50,7 @@ function postQuery(req, res) { var json = JSON.parse(req.requestBody); if (!json || !(json instanceof Object) || json.query == undefined) { - actions.actionResultError (req, res, 400, actions.queryNotModified, "Invalid query data"); + actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid"); return; } @@ -65,7 +65,7 @@ function postQuery(req, res) { actions.actionResultOK(req, res, 200, result); } catch (e) { - actions.actionResultError (req, res, 500, actions.queryNotModified, "Internal server error"); + actions.actionResultError (req, res, 404, actions.errorJavascriptException, "Javascript exception"); } } diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js new file mode 100644 index 0000000000..07b4f47663 --- /dev/null +++ b/js/common/bootstrap/errors.js @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief auto-generated file generated from errors.dat +//////////////////////////////////////////////////////////////////////////////// + +var internal = require("internal"); + +ModuleCache["/internal"].exports.errors = { + "VOC_ERROR_ILLEGAL_STATE" : { "code" : 1000, "message" : "illegal state" }, + "VOC_ERROR_SHAPER_FAILED" : { "code" : 1001, "message" : "illegal shaper" }, + "VOC_ERROR_CORRUPTED_DATAFILE" : { "code" : 1002, "message" : "corrupted datafile" }, + "VOC_ERROR_MMAP_FAILED" : { "code" : 1003, "message" : "mmap failed" }, + "VOC_ERROR_MSYNC_FAILED" : { "code" : 1004, "message" : "msync failed" }, + "VOC_ERROR_NO_JOURNAL" : { "code" : 1005, "message" : "no journal" }, + "VOC_ERROR_DATAFILE_SEALED" : { "code" : 1006, "message" : "datafile sealed" }, + "VOC_ERROR_CORRUPTED_COLLECTION" : { "code" : 1007, "message" : "corrupted collection" }, + "VOC_ERROR_UNKNOWN_TYPE" : { "code" : 1008, "message" : "unknown type" }, + "VOC_ERROR_ILLEGAL_PARAMETER" : { "code" : 1009, "message" : "illegal parameter" }, + "VOC_ERROR_INDEX_EXISTS" : { "code" : 1010, "message" : "index exists" }, + "VOC_ERROR_CONFLICT" : { "code" : 1011, "message" : "conflict" }, + "VOC_ERROR_WRONG_PATH" : { "code" : 1100, "message" : "wrong path" }, + "VOC_ERROR_CANNOT_RENAME" : { "code" : 1101, "message" : "cannot rename" }, + "VOC_ERROR_WRITE_FAILED" : { "code" : 1102, "message" : "write failed" }, + "VOC_ERROR_READ_ONLY" : { "code" : 1103, "message" : "ready only" }, + "VOC_ERROR_DATAFILE_FULL" : { "code" : 1104, "message" : "datafile full" }, + "VOC_ERROR_FILESYSTEM_FULL" : { "code" : 1105, "message" : "filesystem full" }, + "VOC_ERROR_READ_FAILED" : { "code" : 1106, "message" : "read failed" }, + "VOC_ERROR_FILE_NOT_FOUND" : { "code" : 1107, "message" : "file not found" }, + "VOC_ERROR_FILE_NOT_ACCESSIBLE" : { "code" : 1108, "message" : "file not accessible" }, + "VOC_ERROR_DOCUMENT_NOT_FOUND" : { "code" : 1200, "message" : "document not found" }, + "ERROR_QUERY_OOM" : { "code" : 1500, "message" : "out of memory" }, + "ERROR_QUERY_KILLED" : { "code" : 1501, "message" : "query killed" }, + "ERROR_QUERY_PARSE" : { "code" : 1510, "message" : "parse error: %s" }, + "ERROR_QUERY_EMPTY" : { "code" : 1511, "message" : "query is empty" }, + "ERROR_QUERY_SPECIFICATION_INVALID" : { "code" : 1512, "message" : "query specification invalid" }, + "ERROR_QUERY_NUMBER_OUT_OF_RANGE" : { "code" : 1520, "message" : "number '%s' is out of range" }, + "ERROR_QUERY_LIMIT_VALUE_OUT_OF_RANGE" : { "code" : 1521, "message" : "limit value '%s' is out of range" }, + "ERROR_QUERY_TOO_MANY_JOINS" : { "code" : 1540, "message" : "too many joins." }, + "ERROR_QUERY_COLLECTION_NAME_INVALID" : { "code" : 1550, "message" : "collection name '%s' is invalid" }, + "ERROR_QUERY_COLLECTION_ALIAS_INVALID" : { "code" : 1551, "message" : "collection alias '%s' is invalid" }, + "ERROR_QUERY_COLLECTION_ALIAS_REDECLARED" : { "code" : 1552, "message" : "collection alias '%s' is declared multiple times in the same query" }, + "ERROR_QUERY_COLLECTION_ALIAS_UNDECLARED" : { "code" : 1553, "message" : "collection alias '%s' is used but was not declared in the from clause" }, + "ERROR_QUERY_COLLECTION_NOT_FOUND" : { "code" : 1560, "message" : "unable to open collection '%s'" }, + "ERROR_QUERY_GEO_RESTRICTION_INVALID" : { "code" : 1570, "message" : "geo restriction for alias '%s' is invalid" }, + "ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable geo index found for geo restriction on '%s'" }, + "ERROR_QUERY_BIND_PARAMETER_MISSING" : { "code" : 1590, "message" : "no value specified for declared bind parameter '%s'" }, + "ERROR_QUERY_BIND_PARAMETER_REDECLARED" : { "code" : 1591, "message" : "value for bind parameter '%s' is declared multiple times" }, + "ERROR_QUERY_BIND_PARAMETER_UNDECLARED" : { "code" : 1592, "message" : "bind parameter '%s' was not declared in the query" }, + "ERROR_QUERY_BIND_PARAMETER_VALUE_INVALID" : { "code" : 1593, "message" : "invalid value for bind parameter '%s'" }, + "ERROR_QUERY_BIND_PARAMETER_NUMBER_OUT_OF_RANGE" : { "code" : 1594, "message" : "bind parameter number '%s' out of range" }, + "ERROR_CURSOR_NOT_FOUND" : { "code" : 1600, "message" : "cursor not found" }, +}; + diff --git a/js/server/modules/actions.js b/js/server/modules/actions.js index 78477f6974..e2e918e99a 100644 --- a/js/server/modules/actions.js +++ b/js/server/modules/actions.js @@ -41,16 +41,16 @@ var console = require("console"); /// @brief error codes //////////////////////////////////////////////////////////////////////////////// -exports.queryNotFound = 10404; -exports.queryNotModified = 10304; +exports.errorQuerySpecificationInvalid = 1512; +exports.errorCursorNotFound = 1600; + +exports.errorInvalidRequest = 1700; +exports.errorJavascriptException = 1701; exports.collectionNotFound = 20404; exports.documentNotFound = 30404; exports.documentNotModified = 30304; -exports.cursorNotFound = 40404; -exports.cursorNotModified = 40304; - exports.keyValueNotFound = 41404; exports.keyValueNotModified = 41304; diff --git a/js/server/tests/aql-bind.js b/js/server/tests/aql-bind.js index a5c241b23b..4c151c73ed 100644 --- a/js/server/tests/aql-bind.js +++ b/js/server/tests/aql-bind.js @@ -82,14 +82,127 @@ function aqlBindParametersTestSuite () { } //////////////////////////////////////////////////////////////////////////////// -/// @brief check keyword names in select +/// @brief check length of result set for null bind parameter //////////////////////////////////////////////////////////////////////////////// - function testKeywordNamesWhereValid () { - //this.collection.save({ "value1" : i, "value2" : j, "value3" : "test", "value4" : null, "value5" : -13.5}); - var result = this.getQueryResults("SELECT { value: @value1@ } FROM " + this.collection._name + " c WHERE c.value1 == @value1@", { "value1" : 0 }); + function executeRsLengthCheckNull (expectedLength, value) { + var params = { "7" : value }; + var result = this.getQueryResults("SELECT { value: @7 } FROM " + this.collection._name + " c " + + "WHERE c.value4 == @7", params); - assertEqual(11, result.length); + assertEqual(expectedLength, result.length); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check length of result set for string bind parameter +//////////////////////////////////////////////////////////////////////////////// + + function executeRsLengthCheckString (expectedLength, value) { + var params = { "0" : value }; + var result = this.getQueryResults("SELECT { value: @0 } FROM " + this.collection._name + " c " + + "WHERE c.value3 == @0", params); + + assertEqual(expectedLength, result.length); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check length of result set for 1 bind parameter +//////////////////////////////////////////////////////////////////////////////// + + function executeRsLengthCheck (expectedLength, value) { + var params = { "value1" : value }; + var result = this.getQueryResults("SELECT { value: @value1@ } FROM " + this.collection._name + " c " + + "WHERE c.value1 == @value1@", params); + + assertEqual(expectedLength, result.length); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check length of result set for 2 bind parameters +//////////////////////////////////////////////////////////////////////////////// + + function executeRsLengthCheck2 (expectedLength, value1, value2) { + var params = { "value1" : value1, "value2" : value2 }; + var result = this.getQueryResults("SELECT { value: @value1@ } FROM " + this.collection._name + " c " + + "WHERE c.value1 == @value1@ && c.value2 == @value2@", params); + + assertEqual(expectedLength, result.length); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check result sets +//////////////////////////////////////////////////////////////////////////////// + + function testRsLengths1 () { + this.executeRsLengthCheck(11, 0); + this.executeRsLengthCheck(11, 1); + this.executeRsLengthCheck(11, 2); + this.executeRsLengthCheck(11, 9); + this.executeRsLengthCheck(11, 10); + + this.executeRsLengthCheck(0, -1); + this.executeRsLengthCheck(0, -5); + this.executeRsLengthCheck(0, -10); + this.executeRsLengthCheck(0, -11); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check result sets +//////////////////////////////////////////////////////////////////////////////// + + function testRsLengths2 () { + this.executeRsLengthCheck2(1, 0, 0); + this.executeRsLengthCheck2(1, 0, 1); + this.executeRsLengthCheck2(1, 1, 0); + this.executeRsLengthCheck2(1, 2, 0); + this.executeRsLengthCheck2(1, 2, 1); + this.executeRsLengthCheck2(1, 0, 2); + this.executeRsLengthCheck2(1, 1, 2); + this.executeRsLengthCheck2(1, 10, 0); + this.executeRsLengthCheck2(1, 10, 1); + this.executeRsLengthCheck2(1, 0, 10); + this.executeRsLengthCheck2(1, 1, 10); + this.executeRsLengthCheck2(1, 10, 10); + + this.executeRsLengthCheck2(0, 11, 0); + this.executeRsLengthCheck2(0, 11, 1); + this.executeRsLengthCheck2(0, 0, 11); + this.executeRsLengthCheck2(0, 1, 11); + this.executeRsLengthCheck2(0, -1, 0); + this.executeRsLengthCheck2(0, 1, -1); + this.executeRsLengthCheck2(0, 10, -1); + this.executeRsLengthCheck2(0, 11, -1); + this.executeRsLengthCheck2(0, -10, 1); + this.executeRsLengthCheck2(0, -10, 10); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check result sets +//////////////////////////////////////////////////////////////////////////////// + + function testRsLengthsString () { + this.executeRsLengthCheckString(121, "test"); + + this.executeRsLengthCheckString(0, " test"); + this.executeRsLengthCheckString(0, " test "); + this.executeRsLengthCheckString(0, "test "); + this.executeRsLengthCheckString(0, "test "); + this.executeRsLengthCheckString(0, "rest"); + this.executeRsLengthCheckString(0, 15); + this.executeRsLengthCheckString(0, 1); + this.executeRsLengthCheckString(0, -15); + this.executeRsLengthCheckString(0, null); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check result sets +//////////////////////////////////////////////////////////////////////////////// + + function testRsLengthsNull () { + this.executeRsLengthCheckNull(0, "test"); + this.executeRsLengthCheckNull(0, "1"); + this.executeRsLengthCheckNull(0, 1); + this.executeRsLengthCheckNull(0, 2); } }