diff --git a/CHANGELOG b/CHANGELOG index 784b5646c0..4b34fff879 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -98,9 +98,18 @@ v2.8.0 (XXXX-XX-XX) of AQL queries -v2.7.1 (XXXX-XX-XX) +v2.7.2 (XXXX-XX-XX) ------------------- +* fixed potentially invalid pointer access in shaper when the currently accessed + document got re-located by the WAL collector at the very same time + + +v2.7.1 (2015-11-07) +------------------- + +* switch to linenoise next generation + * exclude `_apps` collection from replication The slave has its own `_apps` collection which it populates on server start. @@ -643,7 +652,14 @@ v2.7.0-rc1 (2015-09-17) The "Applications" tab in the web interfaces has been renamed to "Services". -v2.6.10 (XXXX-XX-XX) +v2.6.11 (XXXX-XX-XX) +-------------------- + +* fixed potentially invalid pointer access in shaper when the currently accessed + document got re-located by the WAL collector at the very same time + + +v2.6.10 (2015-11-10) -------------------- * disable replication appliers when starting in modes `--upgrade`, `--no-server` diff --git a/Documentation/Books/Users/Foxx/Develop/Console.mdpp b/Documentation/Books/Users/Foxx/Develop/Console.mdpp index 69ca248d81..c6666cdb1a 100644 --- a/Documentation/Books/Users/Foxx/Develop/Console.mdpp +++ b/Documentation/Books/Users/Foxx/Develop/Console.mdpp @@ -19,6 +19,8 @@ If the first argument is not a formatting string or any of the additional argume **Examples** ```js +var console = require("console"); + console.log("%s, %s!", "Hello", "World"); // => "Hello, World!" console.log("%s, World!", "Hello", "extra"); // => "Hello, World! extra" console.log("Hello,", "beautiful", "world!"); // => "Hello, beautiful world!" diff --git a/Documentation/Books/Users/WebInterface/README.mdpp b/Documentation/Books/Users/WebInterface/README.mdpp index e10fb3d1f4..49c116024f 100644 --- a/Documentation/Books/Users/WebInterface/README.mdpp +++ b/Documentation/Books/Users/WebInterface/README.mdpp @@ -6,8 +6,8 @@ interface can be accessed via the URL http://localhost:8529 assuming you are using the standard port and no user routings. If you -have any application installed, the home page might point to that -application instead. In this case use +have any service installed, the home page might point to that +service instead. In this case use http://localhost:8529/_admin/aardvark/index.html @@ -56,16 +56,16 @@ line to add a new document to the collection. The document will be created instantly, with a system-defined key. The key and all other attributes of the document can be adjusted in the following view. -!SECTION Applications Tab +!SECTION Services Tab -The *Applications* tab provides a list of installed Foxx applications. The view -is divided into lists of installed and applications that are available for +The *Services* tab provides a list of installed Foxx services ( also called applications). The view +is divided into lists of installed and services that are available for installation. -Please note that ArangoDB's web interface (_aardvark_) is a Foxx application -itself. Please also note that installed applications will be listed in both +Please note that ArangoDB's web interface (_aardvark_) is a Foxx service +itself. Please also note that installed services will be listed in both the *installed* and the *available* section. This is intentional because each -application can be installed multiple times using different mount points. +service can be installed multiple times using different mount points. !SECTION Graphs Tab diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index e8b70aad51..28484a6279 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -2283,8 +2283,6 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, if (vertexInfo.isString()) { vertexId = basics::JsonHelper::getStringValue(vertexInfo.json(), ""); if (vertexId.find("/") != std::string::npos) { - - // TODO tmp can be replaced by Traversal::IdStringToVertexId size_t split; char const* str = vertexId.c_str(); @@ -2295,7 +2293,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, std::string const collectionName = vertexId.substr(0, split); if (collectionName.compare(vColName) != 0) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_GRAPH_INVALID_PARAMETER, - "you specified vertex collection `%s` for start vertext from `%s`", + "specified vertex collection '%s' does not match start vertex collection '%s'", vColName.c_str(), collectionName.c_str()); } @@ -2303,7 +2301,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, if (coli == nullptr) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", collectionName.c_str()); } @@ -2320,7 +2318,6 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "NEIGHBORS"); } vertexId = basics::JsonHelper::getStringValue(vertexInfo.get("_id").json(), ""); - // TODO tmp can be replaced by Traversal::IdStringToVertexId size_t split; char const* str = vertexId.c_str(); @@ -2331,7 +2328,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, std::string const collectionName = vertexId.substr(0, split); if (collectionName.compare(vColName) != 0) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_GRAPH_INVALID_PARAMETER, - "you specified vertex collection `%s` for start vertext from `%s`", + "specified vertex collection '%s' does not match start vertex collection '%s'", vColName.c_str(), collectionName.c_str()); } @@ -2339,7 +2336,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, if (coli == nullptr) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", collectionName.c_str()); } @@ -2529,7 +2526,7 @@ AqlValue Functions::Near (triagens::aql::Query* query, true, true); if (res != TRI_ERROR_NO_ERROR) { - THROW_ARANGO_EXCEPTION_FORMAT(res, "`%s`", colName.c_str()); + THROW_ARANGO_EXCEPTION_FORMAT(res, "'%s'", colName.c_str()); } TRI_EnsureCollectionsTransaction(trx->getInternals()); @@ -2537,7 +2534,7 @@ AqlValue Functions::Near (triagens::aql::Query* query, if (collection == nullptr) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", colName.c_str()); } } @@ -2545,9 +2542,9 @@ AqlValue Functions::Near (triagens::aql::Query* query, auto document = trx->documentCollection(cid); if (document == nullptr) { - THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", - colName.c_str()); + THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, + "'%s'", + colName.c_str()); } triagens::arango::Index* index = nullptr; @@ -2699,7 +2696,7 @@ AqlValue Functions::Within (triagens::aql::Query* query, true, true); if (res != TRI_ERROR_NO_ERROR) { - THROW_ARANGO_EXCEPTION_FORMAT(res, "`%s`", colName.c_str()); + THROW_ARANGO_EXCEPTION_FORMAT(res, "'%s'", colName.c_str()); } TRI_EnsureCollectionsTransaction(trx->getInternals()); @@ -2707,7 +2704,7 @@ AqlValue Functions::Within (triagens::aql::Query* query, if (collection == nullptr) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", colName.c_str()); } } @@ -2989,7 +2986,7 @@ static void RegisterCollectionInTransaction (triagens::arango::AqlTransaction* t cid = trx->resolver()->getCollectionId(collectionName); if (cid == 0) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", collectionName.c_str()); } // ensure the collection is loaded @@ -3003,7 +3000,7 @@ static void RegisterCollectionInTransaction (triagens::arango::AqlTransaction* t true, true); if (res != TRI_ERROR_NO_ERROR) { - THROW_ARANGO_EXCEPTION_FORMAT(res, "`%s`", collectionName.c_str()); + THROW_ARANGO_EXCEPTION_FORMAT(res, "'%s'", collectionName.c_str()); } TRI_EnsureCollectionsTransaction(trx->getInternals()); collection = trx->trxCollection(cid); @@ -3245,7 +3242,7 @@ AqlValue Functions::Edges (triagens::aql::Query* query, TRI_voc_cid_t startCid = resolver->getCollectionId(parts[0]); if (startCid == 0) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, - "`%s`", + "'%s'", parts[0].c_str()); } diff --git a/arangod/Aql/TraversalConditionFinder.cpp b/arangod/Aql/TraversalConditionFinder.cpp index 48f7e3c7db..5420875beb 100644 --- a/arangod/Aql/TraversalConditionFinder.cpp +++ b/arangod/Aql/TraversalConditionFinder.cpp @@ -50,7 +50,6 @@ bool checkPathVariableAccessFeasible(CalculationNode const* cn, size_t len = onePath.size(); bool isEdgeAccess = false; bool isVertexAccess = false; - bool isAsterisc = false; size_t attrAccessTo = 0; if (onePath[len - 2]->type == NODE_TYPE_ATTRIBUTE_ACCESS) { @@ -82,7 +81,7 @@ bool checkPathVariableAccessFeasible(CalculationNode const* cn, else if ((onePath[len - 3]->type == NODE_TYPE_ITERATOR) && (onePath[len - 4]->type == NODE_TYPE_EXPANSION)){ // we now need to check for p.edges[*] which becomes a fancy structure - isAsterisc = true; + return false; } else { return false; @@ -118,42 +117,29 @@ bool checkPathVariableAccessFeasible(CalculationNode const* cn, } if (accessNodeBranch->isSimple() && filterByNode->type == NODE_TYPE_VALUE) { - AstNode *newNode = accessNodeBranch->clone(ast); + AstNode *newNode = pathAccessNode->clone(ast); - // since we just copied one path, we should only find one. - newNode->findVariableAccess(currentPath, clonePath, var); - newNode->dump(20); - if (isAsterisc) { - - } - else { + // since we just copied one path, we should only find one. + newNode->findVariableAccess(currentPath, clonePath, var); auto len = clonePath[0].size(); - /// todo len < 4 + if (len < 4) { + // well, if we've gotten here, we can't cluster filter, but + // usual early filtering should be fine. + return true; + } AstNode* firstRefNode = (AstNode*) clonePath[0][len - 4]; TRI_ASSERT(firstRefNode->type == NODE_TYPE_ATTRIBUTE_ACCESS); auto varRefNode = new AstNode(NODE_TYPE_REFERENCE); ast->query()->addNode(varRefNode); varRefNode->setData(isEdgeAccess ? tn->edgeOutVariable(): tn->vertexOutVariable()); firstRefNode->changeMember(0, varRefNode); - tn->storeSimpleExpression(isAsterisc, - isEdgeAccess, + tn->storeSimpleExpression(isEdgeAccess, attrAccessTo, NODE_TYPE_OPERATOR_BINARY_EQ, newNode, filterByNode); - - printf("\n xxxxx: %s\n", newNode->toString().c_str()); - printf("\n yyyy: %s\n", accessNodeBranch->toString().c_str()); - printf("\n yyyy: %s\n", filterByNode->toString().c_str()); - } } -printf("\na: %s\n", compareNode->toString().c_str()); -printf("\na: %s\n", accessNodeBranch->toString().c_str()); - - triagens::basics::Json j(TRI_UNKNOWN_MEM_ZONE, accessNodeBranch->toJson(TRI_UNKNOWN_MEM_ZONE, true)); - printf("sanotuh %s\n", j.toString().c_str()); - } } diff --git a/arangod/Aql/TraversalNode.cpp b/arangod/Aql/TraversalNode.cpp index 8d72d624e0..44d1f4c279 100644 --- a/arangod/Aql/TraversalNode.cpp +++ b/arangod/Aql/TraversalNode.cpp @@ -35,10 +35,16 @@ using namespace triagens::aql; void TraversalNode::simpleTravererExpression::toJson(triagens::basics::Json& json, TRI_memory_zone_t* zone) const { - json("isAsteriscAccess", triagens::basics::Json(isAsteriscAccess)) - ("isEdgeAccess", triagens::basics::Json(isEdgeAccess)) + auto op = AstNode::Operators.find(comparisonType); + + if (op == AstNode::Operators.end()) { + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, "invalid operator for simpleTraverserExpression"); + } + std::string const operatorStr = op->second; + + json("isEdgeAccess", triagens::basics::Json(isEdgeAccess)) ("indexAccess", triagens::basics::Json((int32_t)indexAccess)) - ("comparisonType", triagens::basics::Json("==")) /// TODO more comparison types? + ("comparisonType", triagens::basics::Json(operatorStr)) ("varAccess", varAccess->toJson(zone, true)) ("compareTo", compareTo->toJson(zone, true)); @@ -414,16 +420,14 @@ void TraversalNode::setCondition(triagens::aql::Condition* condition){ _condition = condition; } -void TraversalNode::storeSimpleExpression(bool isAsteriscAccess, - bool isEdgeAccess, +void TraversalNode::storeSimpleExpression(bool isEdgeAccess, size_t indexAccess, AstNodeType comparisonType, AstNode const* varAccess, AstNode const* compareTo) { simpleTravererExpression e { - isAsteriscAccess, - isEdgeAccess, + isEdgeAccess, indexAccess, comparisonType, varAccess, diff --git a/arangod/Aql/TraversalNode.h b/arangod/Aql/TraversalNode.h index 1183f238ab..997b6036f2 100644 --- a/arangod/Aql/TraversalNode.h +++ b/arangod/Aql/TraversalNode.h @@ -50,7 +50,6 @@ namespace triagens { friend class TraversalCollectionBlock; struct simpleTravererExpression { - bool isAsteriscAccess; bool isEdgeAccess; size_t indexAccess; AstNodeType comparisonType; @@ -341,8 +340,7 @@ namespace triagens { /// @brief Remember a simple comparator filter //////////////////////////////////////////////////////////////////////////////// - void storeSimpleExpression(bool isAsteriscAccess, - bool isEdgeAccess, + void storeSimpleExpression(bool isEdgeAccess, size_t indexAccess, AstNodeType comparisonType, AstNode const* varAccess, diff --git a/arangod/VocBase/collection.cpp b/arangod/VocBase/collection.cpp index 323acb7828..2c6e32b868 100644 --- a/arangod/VocBase/collection.cpp +++ b/arangod/VocBase/collection.cpp @@ -33,6 +33,7 @@ #include "Basics/conversions.h" #include "Basics/files.h" +#include "Basics/hashes.h" #include "Basics/json.h" #include "Basics/JsonHelper.h" #include "Basics/logging.h" diff --git a/arangod/VocBase/document-collection.h b/arangod/VocBase/document-collection.h index 1dc9515365..a58b305357 100644 --- a/arangod/VocBase/document-collection.h +++ b/arangod/VocBase/document-collection.h @@ -212,12 +212,12 @@ struct TRI_doc_mptr_t { if (marker->_type == TRI_DOC_MARKER_KEY_DOCUMENT || marker->_type == TRI_DOC_MARKER_KEY_EDGE) { auto offset = (reinterpret_cast(marker))->_offsetJson; - return static_cast(_dataptr) + offset; + return reinterpret_cast(marker) + offset; } else if (marker->_type == TRI_WAL_MARKER_DOCUMENT || marker->_type == TRI_WAL_MARKER_EDGE) { auto offset = (reinterpret_cast(marker))->_offsetJson; - return static_cast(_dataptr) + offset; + return reinterpret_cast(marker) + offset; } TRI_ASSERT(false); diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h index e3fb0dcb0b..de6b0754f7 100644 --- a/arangod/VocBase/transaction.h +++ b/arangod/VocBase/transaction.h @@ -32,9 +32,6 @@ #include "Basics/Common.h" -#include "Basics/hashes.h" -#include "Basics/locks.h" -#include "Basics/vector.h" #include "VocBase/datafile.h" #include "VocBase/voc-types.h" diff --git a/js/server/modules/org/arangodb/aql.js b/js/server/modules/org/arangodb/aql.js index c4bf6439d1..298c5c0119 100644 --- a/js/server/modules/org/arangodb/aql.js +++ b/js/server/modules/org/arangodb/aql.js @@ -412,7 +412,7 @@ function WARN (func, error, data) { /// @brief throw a runtime exception //////////////////////////////////////////////////////////////////////////////// -function THROW (func, error, data) { +function THROW (func, error, data, moreMessage) { 'use strict'; var prefix = ""; @@ -429,6 +429,9 @@ function THROW (func, error, data) { else { err.errorMessage = prefix + error.message; } + if (moreMessage !== undefined) { + err.errorMessage += "; " + moreMessage; + } throw err; } @@ -7422,6 +7425,15 @@ function AQL_NEIGHBORS (vertexCollection, 'use strict'; vertex = TO_ID(vertex, vertexCollection); + var collectionFromVertex = vertex.slice(0, vertexCollection.length); + if (collectionFromVertex !== vertexCollection) { + THROW("AQL_NEIGBORS", + INTERNAL.errors.ERROR_ARANGO_DOCUMENT_KEY_BAD, + "", + "You specified vertex collection `" + collectionFromVertex + + "...` for start vertext from the collection`" + vertexCollection + "`"); + + } options = CLONE(options) || {}; // Fallback to JS if we are in the cluster // Improve the examples. LocalServer can match String -> _id diff --git a/js/server/modules/org/arangodb/testing.js b/js/server/modules/org/arangodb/testing.js index b86ab16538..08b35179a6 100644 --- a/js/server/modules/org/arangodb/testing.js +++ b/js/server/modules/org/arangodb/testing.js @@ -156,6 +156,7 @@ var allTests = "shell_client", "dump", "arangob", + "arangosh", "importing", "upgrade", "authentication", @@ -1544,6 +1545,48 @@ function runArangoBenchmark (options, instanceInfo, cmds) { return executeAndWait(exe, toArgv(args)); } +testFuncs.arangosh = function (options) { + var failed = 0; + var args = makeTestingArgsClient(options); + var arangosh = fs.join("bin","arangosh"); + + print("Starting arangosh with exception throwing script:"); + args["javascript.execute-string"] = "throw('foo')"; + var rc = executeExternalAndWait(arangosh, toArgv(args)); + var failSuccess = (rc.hasOwnProperty('exit') && rc.exit === 1); + if (!failSuccess) { + failed += 1; + } + + print("Starting arangosh with regular terminating script:"); + args["javascript.execute-string"] = ";"; + rc = executeExternalAndWait(arangosh, toArgv(args)); + var successSuccess = (rc.hasOwnProperty('exit') && rc.exit === 0); + if (!successSuccess) { + failed += 1; + } + + return [ + { + "suiteName": "ArangoshExitCodeTest", + "testArangoshExitCodeFail": + { + "status": failSuccess, + "duration": 0 + }, + "testArangoshExitCodeSuccess": + { + "status": successSuccess, + "duration": 0 + }, + "duration": 0, + "status": failSuccess && successSuccess, + "failed": failed, + "total": 2 + } + ]; +}; + var impTodo = [ {id: "json1", data: makePathUnix("UnitTests/import-1.json"), coll: "UnitTestsImportJson1", type: "json", create: undefined},