diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index ac461c4dad..bc3f6c3f74 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -141,9 +141,11 @@ Ast::~Ast() {} //////////////////////////////////////////////////////////////////////////////// /// @brief convert the AST into JSON /// the caller is responsible for freeing the JSON later +/// @DEPRECATED //////////////////////////////////////////////////////////////////////////////// TRI_json_t* Ast::toJson(TRI_memory_zone_t* zone, bool verbose) const { +#warning Deprecated TRI_json_t* json = TRI_CreateArrayJson(zone); if (json == nullptr) { @@ -160,6 +162,19 @@ TRI_json_t* Ast::toJson(TRI_memory_zone_t* zone, bool verbose) const { return json; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert the AST into VelocyPack +//////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr Ast::toVelocyPack(bool verbose) const { + auto builder = std::make_shared(); + { + VPackArrayBuilder guard(builder.get()); + _root->toVelocyPack(*builder, verbose); + } + return builder; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief destroy the AST //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index 2fe5d17551..0cd79f5734 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -184,10 +184,17 @@ class Ast { ////////////////////////////////////////////////////////////////////////////// /// @brief convert the AST into JSON /// the caller is responsible for freeing the JSON later + /// @DEPRECATED ////////////////////////////////////////////////////////////////////////////// TRI_json_t* toJson(TRI_memory_zone_t*, bool) const; + ////////////////////////////////////////////////////////////////////////////// + /// @brief convert the AST into JSON + ////////////////////////////////////////////////////////////////////////////// + + std::shared_ptr toVelocyPack(bool) const; + ////////////////////////////////////////////////////////////////////////////// /// @brief add an operation to the root node ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index 424f2a15ea..fcffbd09f4 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -472,6 +472,7 @@ struct CoordinatorInstanciator : public WalkerWorker { EngineInfo const& info, Collection* collection, QueryId& connectedId, std::string const& shardId, TRI_json_t* jsonPlan) { +#warning still Json inplace. Needs to be fixed // create a JSON representation of the plan Json result(Json::Object); @@ -487,8 +488,10 @@ struct CoordinatorInstanciator : public WalkerWorker { "type", Json(TRI_TransactionTypeGetStr(collection->accessType)))); jsonNodesList.set("collections", jsonCollectionsList); - jsonNodesList.set("variables", - query->ast()->variables()->toJson(TRI_UNKNOWN_MEM_ZONE)); + + VPackBuilder tmp; + query->ast()->variables()->toVelocyPack(tmp); + jsonNodesList.set("variables", arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice())); result.set("plan", jsonNodesList); if (info.part == arangodb::aql::PART_MAIN) { diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index 705b32d060..d94927021d 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -214,10 +214,12 @@ ExecutionPlan* ExecutionPlan::clone(Query const& query) { //////////////////////////////////////////////////////////////////////////////// /// @brief export to JSON, returns an AUTOFREE Json object +/// DEPRECATED //////////////////////////////////////////////////////////////////////////////// arangodb::basics::Json ExecutionPlan::toJson(Ast* ast, TRI_memory_zone_t* zone, bool verbose) const { +#warning Remove this // TODO VPackBuilder b; _root->toVelocyPack(b, verbose); @@ -247,7 +249,10 @@ arangodb::basics::Json ExecutionPlan::toJson(Ast* ast, TRI_memory_zone_t* zone, } result.set("collections", jsonCollectionList); - result.set("variables", ast->variables()->toJson(TRI_UNKNOWN_MEM_ZONE)); + + VPackBuilder tmpTwo; + ast->variables()->toVelocyPack(tmpTwo); + result.set("variables", arangodb::basics::VelocyPackHelper::velocyPackToJson(tmpTwo.slice())); size_t nrItems = 0; result.set("estimatedCost", arangodb::basics::Json(_root->getCost(nrItems))); result.set("estimatedNrItems", @@ -256,6 +261,41 @@ arangodb::basics::Json ExecutionPlan::toJson(Ast* ast, TRI_memory_zone_t* zone, return result; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief export to VelocyPack +//////////////////////////////////////////////////////////////////////////////// + +void ExecutionPlan::toVelocyPack(Ast* ast, bool verbose, + VPackBuilder& builder) const { + _root->toVelocyPack(builder, verbose); + // set up rules + auto appliedRules(Optimizer::translateRules(_appliedRules)); + + builder.add(VPackValue("rules")); + { + VPackArrayBuilder guard(&builder); + for (auto const& r : appliedRules) { + builder.add(VPackValue(r)); + } + } + builder.add(VPackValue("collections")); + auto usedCollections = *ast->query()->collections()->collections(); + { + VPackArrayBuilder guard(&builder); + for (auto const& c : usedCollections) { + VPackObjectBuilder objGuard(&builder); + builder.add("name", VPackValue(c.first)); + builder.add("type", + VPackValue(TRI_TransactionTypeGetStr(c.second->accessType))); + } + } + builder.add(VPackValue("variables")); + ast->variables()->toVelocyPack(builder); + size_t nrItems = 0; + builder.add("estimatedCost", VPackValue(_root->getCost(nrItems))); + builder.add("estimatedNrItems", VPackValue(nrItems)); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief get a list of all applied rules //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index 038483a1c0..be90a61155 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -96,6 +96,12 @@ class ExecutionPlan { arangodb::basics::Json toJson(Ast* ast, TRI_memory_zone_t* zone, bool verbose) const; + ////////////////////////////////////////////////////////////////////////////// + /// @brief export to VelocyPack + ////////////////////////////////////////////////////////////////////////////// + + void toVelocyPack(Ast*, bool, arangodb::velocypack::Builder&) const; + ////////////////////////////////////////////////////////////////////////////// /// @brief check if the plan is empty ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Parser.cpp b/arangod/Aql/Parser.cpp index 7d06d5fba5..4ec0f17818 100644 --- a/arangod/Aql/Parser.cpp +++ b/arangod/Aql/Parser.cpp @@ -117,7 +117,7 @@ QueryResult Parser::parse(bool withDetails) { if (withDetails) { result.collectionNames = _query->collectionNames(); result.bindParameters = _ast->bindParameters(); - result.json = _ast->toJson(TRI_UNKNOWN_MEM_ZONE, false); + result.result = _ast->toVelocyPack(false); } return result; diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 589a90ffd4..c94aca1bf5 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -612,19 +612,10 @@ QueryResult Query::execute(QueryRegistry* registry) { if (cacheEntry != nullptr) { // got a result from the query cache QueryResult res(TRI_ERROR_NO_ERROR); -#warning Replace QueryResult with VPack - VPackBuilder tmp; - tmp.openObject(); - warningsToVelocyPack(tmp); - tmp.close(); - res.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); - res.json = arangodb::basics::VelocyPackHelper::velocyPackToJson(cacheEntry->_queryResult->slice()); + res.warnings = warningsToVelocyPack(); + TRI_ASSERT(cacheEntry->_queryResult != nullptr); + res.result = cacheEntry->_queryResult; res.cached = true; - - if (res.json == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - return res; } } @@ -650,14 +641,13 @@ QueryResult Query::execute(QueryRegistry* registry) { useQueryCache = false; } - arangodb::basics::Json jsonResult(arangodb::basics::Json::Array, 16); - - // this is the RegisterId our results can be found in - auto const resultRegister = _engine->resultRegister(); - AqlItemBlock* value = nullptr; - + auto resultBuilder = std::make_shared(); try { + VPackArrayBuilder guard(resultBuilder.get()); + // this is the RegisterId our results can be found in + auto const resultRegister = _engine->resultRegister(); + if (useQueryCache) { // iterate over result, return it and store it in query cache while (nullptr != (value = _engine->getSome( @@ -665,14 +655,12 @@ QueryResult Query::execute(QueryRegistry* registry) { auto doc = value->getDocumentCollection(resultRegister); size_t const n = value->size(); - // reserve space for n additional results at once - jsonResult.reserve(n); for (size_t i = 0; i < n; ++i) { auto val = value->getValueReference(i, resultRegister); if (!val.isEmpty()) { - jsonResult.add(val.toJson(_trx, doc, true)); + val.toVelocyPack(_trx, doc, *resultBuilder); } } delete value; @@ -681,14 +669,8 @@ QueryResult Query::execute(QueryRegistry* registry) { if (_warnings.empty()) { // finally store the generated result in the query cache - std::shared_ptr copy(arangodb::basics::JsonHelper::toVelocyPack(jsonResult.json())); - - if (copy == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - auto result = QueryCache::instance()->store( - _vocbase, queryStringHash, _queryString, _queryLength, copy, + _vocbase, queryStringHash, _queryString, _queryLength, resultBuilder, _trx->collectionNames()); if (result == nullptr) { @@ -702,14 +684,11 @@ QueryResult Query::execute(QueryRegistry* registry) { auto doc = value->getDocumentCollection(resultRegister); size_t const n = value->size(); - // reserve space for n additional results at once - jsonResult.reserve(n); - for (size_t i = 0; i < n; ++i) { auto val = value->getValueReference(i, resultRegister); if (!val.isEmpty()) { - jsonResult.add(val.toJson(_trx, doc, true)); + val.toVelocyPack(_trx, doc, *resultBuilder); } } delete value; @@ -732,13 +711,8 @@ QueryResult Query::execute(QueryRegistry* registry) { enterState(FINALIZATION); QueryResult result(TRI_ERROR_NO_ERROR); -#warning Replace QueryResult with VPack - VPackBuilder tmp; - tmp.openObject(); - warningsToVelocyPack(tmp); - tmp.close(); - result.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); - result.json = jsonResult.steal(); + result.warnings = warningsToVelocyPack(); + result.result = resultBuilder; result.stats = stats; if (_profile != nullptr && profiling()) { @@ -890,12 +864,7 @@ QueryResultV8 Query::executeV8(v8::Isolate* isolate, QueryRegistry* registry) { enterState(FINALIZATION); -#warning Replace QueryResult with VPack - VPackBuilder tmp; - tmp.openObject(); - warningsToVelocyPack(tmp); - tmp.close(); - result.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); + result.warnings = warningsToVelocyPack(); result.stats = stats; if (_profile != nullptr && profiling()) { @@ -996,21 +965,21 @@ QueryResult Query::explain() { QueryResult result(TRI_ERROR_NO_ERROR); QueryRegistry localRegistry; + result.result = std::make_shared(); if (allPlans()) { - arangodb::basics::Json out(Json::Array); + { + VPackArrayBuilder guard(result.result.get()); - auto plans = opt.getPlans(); - for (auto& it : plans) { - TRI_ASSERT(it != nullptr); + auto plans = opt.getPlans(); + for (auto& it : plans) { + TRI_ASSERT(it != nullptr); - it->findVarUsage(); - it->planRegisters(); - out.add(it->toJson(parser.ast(), TRI_UNKNOWN_MEM_ZONE, verbosePlans())); + it->findVarUsage(); + it->planRegisters(); + it->toVelocyPack(parser.ast(), verbosePlans(), *result.result); + } } - - result.json = out.steal(); - // cacheability not available here result.cached = false; } else { @@ -1021,9 +990,7 @@ QueryResult Query::explain() { bestPlan->findVarUsage(); bestPlan->planRegisters(); - result.json = - bestPlan->toJson(parser.ast(), TRI_UNKNOWN_MEM_ZONE, verbosePlans()) - .steal(); + bestPlan->toVelocyPack(parser.ast(), verbosePlans(), *result.result); // cacheability result.cached = (_queryString != nullptr && _queryLength > 0 && @@ -1033,12 +1000,7 @@ QueryResult Query::explain() { _trx->commit(); -#warning Replace QueryResult with VPack - VPackBuilder tmp; - tmp.openObject(); - warningsToVelocyPack(tmp); - tmp.close(); - result.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); + result.warnings = warningsToVelocyPack(); result.stats = opt._stats.toVelocyPack(); @@ -1237,7 +1199,8 @@ bool Query::getBooleanOption(char const* option, bool defaultValue) const { /// warnings. If there are none it will not modify the builder ////////////////////////////////////////////////////////////////////////////// -void Query::warningsToVelocyPack(arangodb::velocypack::Builder& builder) const { +void Query::addWarningsToVelocyPackObject( + arangodb::velocypack::Builder& builder) const { TRI_ASSERT(builder.isOpenObject()); if (_warnings.empty()) { return; @@ -1254,6 +1217,28 @@ void Query::warningsToVelocyPack(arangodb::velocypack::Builder& builder) const { } } + +////////////////////////////////////////////////////////////////////////////// +/// @brief transform the list of warnings to VelocyPack. +////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr Query::warningsToVelocyPack() const { + if (_warnings.empty()) { + return nullptr; + } + auto result = std::make_shared(); + { + VPackArrayBuilder guard(result.get()); + size_t const n = _warnings.size(); + for (size_t i = 0; i < n; ++i) { + VPackObjectBuilder objGuard(result.get()); + result->add("code", VPackValue(_warnings[i].first)); + result->add("message", VPackValue(_warnings[i].second)); + } + } + return result; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief initializes the query //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Query.h b/arangod/Aql/Query.h index fd736ef4dd..b716083037 100644 --- a/arangod/Aql/Query.h +++ b/arangod/Aql/Query.h @@ -398,12 +398,19 @@ class Query { bool getBooleanOption(char const*, bool) const; ////////////////////////////////////////////////////////////////////////////// - /// @brief convert the list of warnings to VelocyPack. + /// @brief add the list of warnings to VelocyPack. /// Will add a new entry { ..., warnings: , } if there are /// warnings. If there are none it will not modify the builder ////////////////////////////////////////////////////////////////////////////// - void warningsToVelocyPack(arangodb::velocypack::Builder&) const; + void addWarningsToVelocyPackObject(arangodb::velocypack::Builder&) const; + + ////////////////////////////////////////////////////////////////////////////// + /// @brief transform the list of warnings to VelocyPack. + /// NOTE: returns nullptr if there are no warnings. + ////////////////////////////////////////////////////////////////////////////// + + std::shared_ptr warningsToVelocyPack() const; ////////////////////////////////////////////////////////////////////////////// /// @brief fetch the global query tracking value diff --git a/arangod/Aql/QueryResult.h b/arangod/Aql/QueryResult.h index 783d765ade..91f1a0dee2 100644 --- a/arangod/Aql/QueryResult.h +++ b/arangod/Aql/QueryResult.h @@ -40,19 +40,15 @@ struct QueryResult { code = other.code; cached = other.cached; details = other.details; - warnings = other.warnings; - json = other.json; - stats = other.stats; - profile = other.profile; - zone = other.zone; + warnings.swap(other.warnings); + result.swap(other.result); + stats.swap(other.stats); + profile.swap(other.profile); + clusterplan = other.clusterplan; bindParameters = other.bindParameters; collectionNames = other.collectionNames; - other.warnings = nullptr; - other.json = nullptr; - other.stats = nullptr; - other.profile = nullptr; other.clusterplan = nullptr; } @@ -60,9 +56,8 @@ struct QueryResult { : code(code), cached(false), details(details), - zone(TRI_UNKNOWN_MEM_ZONE), warnings(nullptr), - json(nullptr), + result(nullptr), profile(nullptr), clusterplan(nullptr) {} @@ -71,12 +66,6 @@ struct QueryResult { QueryResult() : QueryResult(TRI_ERROR_NO_ERROR) {} virtual ~QueryResult() { - if (warnings != nullptr) { - TRI_FreeJson(zone, warnings); - } - if (json != nullptr) { - TRI_FreeJson(zone, json); - } } int code; @@ -84,9 +73,8 @@ struct QueryResult { std::string details; std::unordered_set bindParameters; std::vector collectionNames; - TRI_memory_zone_t* zone; - TRI_json_t* warnings; - TRI_json_t* json; + std::shared_ptr warnings; + std::shared_ptr result; std::shared_ptr stats; std::shared_ptr profile; TRI_json_t* clusterplan; diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index a227d56d8e..b8aa6191b1 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -202,14 +202,9 @@ void RestAqlHandler::parseQuery() { answerBuilder.add(VPackValue(p)); } } -#warning res.json has to be replaced by VPack in first-place answerBuilder.add(VPackValue("ast")); - int errCode = JsonHelper::toVelocyPack(res.json, answerBuilder); - if (errCode != TRI_ERROR_NO_ERROR) { -#warning only temporary, wrong error does not matter at all. - generateError(HttpResponse::BAD, errCode); - } - res.json = nullptr; + answerBuilder.add(res.result->slice()); + res.result = nullptr; } catch (...) { generateError(HttpResponse::BAD, TRI_ERROR_OUT_OF_MEMORY, "out of memory"); @@ -259,19 +254,14 @@ void RestAqlHandler::explainQuery() { VPackBuilder answerBuilder; try { VPackObjectBuilder guard(&answerBuilder); - if (res.json != nullptr) { -#warning QueryResult needs to be replaced by VPack + if (res.result != nullptr) { if (query->allPlans()) { answerBuilder.add(VPackValue("plans")); } else { answerBuilder.add(VPackValue("plan")); } - int errCode = JsonHelper::toVelocyPack(res.json, answerBuilder); - if (errCode != TRI_ERROR_NO_ERROR) { -#warning only temporary, wrong error does not matter at all. - generateError(HttpResponse::BAD, errCode); - } - res.json = nullptr; + answerBuilder.add(res.result->slice()); + res.result = nullptr; } } catch (...) { generateError(HttpResponse::BAD, TRI_ERROR_OUT_OF_MEMORY, @@ -842,7 +832,7 @@ void RestAqlHandler::handleUseQuery(std::string const& operation, Query* query, query->getStats(answerBuilder); // return warnings if present - query->warningsToVelocyPack(answerBuilder); + query->addWarningsToVelocyPackObject(answerBuilder); // delete the query from the registry _queryRegistry->destroy(_vocbase, _qId, errorCode); diff --git a/arangod/Aql/VariableGenerator.cpp b/arangod/Aql/VariableGenerator.cpp index a9b14f64fc..7a8e057112 100644 --- a/arangod/Aql/VariableGenerator.cpp +++ b/arangod/Aql/VariableGenerator.cpp @@ -217,18 +217,14 @@ std::string VariableGenerator::nextName() { } //////////////////////////////////////////////////////////////////////////////// -/// @brief export to JSON, returns an AUTOFREE Json object +/// @brief export to VelocyPack //////////////////////////////////////////////////////////////////////////////// -arangodb::basics::Json VariableGenerator::toJson( - TRI_memory_zone_t* zone) const { - Json jsonAllVariablesList(Json::Array, _variables.size()); - +void VariableGenerator::toVelocyPack(VPackBuilder& builder) const { + VPackArrayBuilder guard(&builder); for (auto const& oneVariable : _variables) { - jsonAllVariablesList(oneVariable.second->toJson()); + oneVariable.second->toVelocyPack(builder); } - - return jsonAllVariablesList; } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/VariableGenerator.h b/arangod/Aql/VariableGenerator.h index cbb3db1636..431ea1f39c 100644 --- a/arangod/Aql/VariableGenerator.h +++ b/arangod/Aql/VariableGenerator.h @@ -107,11 +107,11 @@ class VariableGenerator { std::string nextName(); - ////////////////////////////////////////////////////////////////////////////// - /// @brief export to JSON, returns an AUTOFREE Json object - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief export to VelocyPack + //////////////////////////////////////////////////////////////////////////////// - arangodb::basics::Json toJson(TRI_memory_zone_t*) const; + void toVelocyPack(arangodb::velocypack::Builder& builder) const; ////////////////////////////////////////////////////////////////////////////// /// @brief import from VelocyPack diff --git a/arangod/RestHandler/RestCursorHandler.cpp b/arangod/RestHandler/RestCursorHandler.cpp index 63357622e0..033db261f7 100644 --- a/arangod/RestHandler/RestCursorHandler.cpp +++ b/arangod/RestHandler/RestCursorHandler.cpp @@ -131,7 +131,13 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { THROW_ARANGO_EXCEPTION_MESSAGE(queryResult.code, queryResult.details); } - TRI_ASSERT(TRI_IsArrayJson(queryResult.json)); + VPackSlice qResult = queryResult.result->slice(); + + if (qResult.isNone()) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); + } + + TRI_ASSERT(qResult.isArray()); { createResponse(HttpResponse::CREATED); @@ -143,7 +149,7 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { size_t batchSize = arangodb::basics::VelocyPackHelper::getNumericValue( opts, "batchSize", 1000); - size_t const n = TRI_LengthArrayJson(queryResult.json); + size_t const n = static_cast(qResult.length()); if (n <= batchSize) { // result is smaller than batchSize and will be returned directly. no need @@ -153,10 +159,7 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { try { VPackObjectBuilder b(&result); result.add(VPackValue("result")); - int res = arangodb::basics::JsonHelper::toVelocyPack(queryResult.json, result); - if (res != TRI_ERROR_NO_ERROR) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } + result.add(qResult); result.add("hasMore", VPackValue(false)); if (arangodb::basics::VelocyPackHelper::getBooleanValue(opts, "count", false)) { @@ -192,19 +195,9 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { bool count = arangodb::basics::VelocyPackHelper::getBooleanValue( opts, "count", false); - // steal the query JSON, cursor will take over the ownership - auto j = queryResult.json; - std::shared_ptr builder = arangodb::basics::JsonHelper::toVelocyPack(j); - { - // Temporarily validate that transformation actually worked. - // Can be removed again as soon as queryResult returns VPack - VPackSlice validate = builder->slice(); - if (validate.isNone() && j != nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - } + // steal the query result, cursor will take over the ownership arangodb::JsonCursor* cursor = cursors->createFromVelocyPack( - builder, batchSize, extra, ttl, count, queryResult.cached); + queryResult.result, batchSize, extra, ttl, count, queryResult.cached); try { _response->body().appendChar('{'); @@ -358,10 +351,7 @@ std::shared_ptr RestCursorHandler::buildExtra( extra->close(); } else { extra->add(VPackValue("warnings")); - int res = arangodb::basics::JsonHelper::toVelocyPack(queryResult.warnings, *extra); - if (res != TRI_ERROR_NO_ERROR) { - return nullptr; - } + extra->add(queryResult.warnings->slice()); } } catch (...) { return nullptr; diff --git a/arangod/RestHandler/RestQueryHandler.cpp b/arangod/RestHandler/RestQueryHandler.cpp index 54acfdeb60..fdead7020e 100644 --- a/arangod/RestHandler/RestQueryHandler.cpp +++ b/arangod/RestHandler/RestQueryHandler.cpp @@ -390,14 +390,10 @@ bool RestQueryHandler::parseQuery() { } result.close(); // bindVars - auto tmp = VPackParser::fromJson( - arangodb::basics::JsonHelper::toString(parseResult.json)); - result.add("ast", tmp->slice()); + result.add("ast", parseResult.result->slice()); if (parseResult.warnings != nullptr) { - auto tmp = VPackParser::fromJson( - arangodb::basics::JsonHelper::toString(parseResult.warnings)); - result.add("warnings", tmp->slice()); + result.add("warnings", parseResult.warnings->slice()); } } diff --git a/arangod/RestHandler/RestSimpleHandler.cpp b/arangod/RestHandler/RestSimpleHandler.cpp index 2c40b1b4f8..2de4f6e2a7 100644 --- a/arangod/RestHandler/RestSimpleHandler.cpp +++ b/arangod/RestHandler/RestSimpleHandler.cpp @@ -333,18 +333,19 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) { } size_t resultSize = 10; - if (TRI_IsArrayJson(queryResult.json)) { - resultSize = TRI_LengthArrayJson(queryResult.json); + VPackSlice qResult = queryResult.result->slice(); + if (qResult.isArray()) { + resultSize = static_cast(qResult.length()); } + VPackBuilder result; { + VPackObjectBuilder guard(&result); createResponse(HttpResponse::OK); _response->setContentType("application/json; charset=utf-8"); - arangodb::basics::Json result(arangodb::basics::Json::Object, 3); - if (TRI_IsArrayJson(queryResult.json)) { - size_t const n = TRI_LengthArrayJson(queryResult.json); + if (qResult.isArray()) { // This is for internal use of AQL Traverser only. // Should not be documented @@ -370,54 +371,49 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) { expression.release(); } } + + result.add(VPackValue("documents")); + std::vector filteredIds; - arangodb::basics::Json filteredDocuments( - arangodb::basics::Json::Array, n); - arangodb::basics::Json filteredIds(arangodb::basics::Json::Array); - - for (size_t i = 0; i < n; ++i) { - TRI_json_t const* tmp = TRI_LookupArrayJson(queryResult.json, i); - if (tmp != nullptr) { + result.openArray(); + for (auto const& tmp : VPackArrayIterator(qResult)) { + if (!tmp.isNone()) { bool add = true; for (auto& e : expressions) { if (!e->isEdgeAccess && !e->matchesCheck(tmp)) { add = false; - try { - std::string _id = - arangodb::basics::JsonHelper::checkAndGetStringValue( - tmp, "_id"); - arangodb::basics::Json tmp(_id); - filteredIds.add(tmp.steal()); - } catch (...) { - // This should never occur. - } + std::string _id = + arangodb::basics::VelocyPackHelper::checkAndGetStringValue( + tmp, "_id"); + filteredIds.emplace_back(_id); break; } } if (add) { - filteredDocuments.add(TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, tmp)); + result.add(tmp); } } } + result.close(); - result.set("documents", filteredDocuments); - result.set("filtered", filteredIds); + result.add(VPackValue("filtered")); + result.openArray(); + for (auto const& it : filteredIds) { + result.add(VPackValue(it)); + } + result.close(); } else { - result.set("documents", arangodb::basics::Json( - TRI_UNKNOWN_MEM_ZONE, queryResult.json, - arangodb::basics::Json::AUTOFREE)); - queryResult.json = nullptr; + result.add(VPackValue("documents")); + result.add(qResult); + queryResult.result = nullptr; } } else { - result.set("documents", arangodb::basics::Json( - TRI_UNKNOWN_MEM_ZONE, queryResult.json, - arangodb::basics::Json::AUTOFREE)); - queryResult.json = nullptr; + result.add(VPackValue("documents")); + result.add(qResult); + queryResult.result = nullptr; } - - result.set("error", arangodb::basics::Json(false)); - result.set("code", arangodb::basics::Json( - static_cast(_response->responseCode()))); + result.add("error", VPackValue(false)); + result.add("code", VPackValue(_response->responseCode())); // reserve 48 bytes per result document by default int res = _response->body().reserve(48 * resultSize); @@ -426,7 +422,10 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) { THROW_ARANGO_EXCEPTION(res); } - result.dump(_response->body()); + arangodb::basics::VPackStringBufferAdapter buffer( + _response->body().stringBuffer()); + VPackDumper dumper(&buffer); + dumper.dump(result.slice()); } } catch (arangodb::basics::Exception const& ex) { unregisterQuery(); diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index d252132d14..2b144f10c7 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1028,13 +1028,13 @@ static void JS_ParseAql(v8::FunctionCallbackInfo const& args) { } result->Set(TRI_V8_ASCII_STRING("ast"), - TRI_ObjectJson(isolate, parseResult.json)); + TRI_VPackToV8(isolate, parseResult.result->slice())); if (parseResult.warnings == nullptr) { result->Set(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); } else { result->Set(TRI_V8_ASCII_STRING("warnings"), - TRI_ObjectJson(isolate, parseResult.warnings)); + TRI_VPackToV8(isolate, parseResult.warnings->slice())); } TRI_V8_RETURN(result); @@ -1147,13 +1147,13 @@ static void JS_ExplainAql(v8::FunctionCallbackInfo const& args) { } v8::Handle result = v8::Object::New(isolate); - if (queryResult.json != nullptr) { + if (queryResult.result != nullptr) { if (query.allPlans()) { result->Set(TRI_V8_ASCII_STRING("plans"), - TRI_ObjectJson(isolate, queryResult.json)); + TRI_VPackToV8(isolate, queryResult.result->slice())); } else { result->Set(TRI_V8_ASCII_STRING("plan"), - TRI_ObjectJson(isolate, queryResult.json)); + TRI_VPackToV8(isolate, queryResult.result->slice())); result->Set(TRI_V8_ASCII_STRING("cacheable"), v8::Boolean::New(isolate, queryResult.cached)); } @@ -1167,7 +1167,7 @@ static void JS_ExplainAql(v8::FunctionCallbackInfo const& args) { result->Set(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); } else { result->Set(TRI_V8_ASCII_STRING("warnings"), - TRI_ObjectJson(isolate, queryResult.warnings)); + TRI_VPackToV8(isolate, queryResult.warnings->slice())); } if (queryResult.stats != nullptr) { VPackSlice stats = queryResult.stats->slice(); @@ -1240,9 +1240,9 @@ static void JS_ExecuteAqlJson(v8::FunctionCallbackInfo const& args) { // return the array value as it is. this is a performance optimisation v8::Handle result = v8::Object::New(isolate); - if (queryResult.json != nullptr) { + if (queryResult.result != nullptr) { result->ForceSet(TRI_V8_ASCII_STRING("json"), - TRI_ObjectJson(isolate, queryResult.json)); + TRI_VPackToV8(isolate, queryResult.result->slice())); } if (queryResult.stats != nullptr) { VPackSlice stats = queryResult.stats->slice(); @@ -1259,7 +1259,7 @@ static void JS_ExecuteAqlJson(v8::FunctionCallbackInfo const& args) { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); } else { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), - TRI_ObjectJson(isolate, queryResult.warnings)); + TRI_VPackToV8(isolate, queryResult.warnings->slice())); } result->ForceSet(TRI_V8_ASCII_STRING("cached"), v8::Boolean::New(isolate, queryResult.cached)); @@ -1365,7 +1365,7 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); } else { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), - TRI_ObjectJson(isolate, queryResult.warnings)); + TRI_VPackToV8(isolate, queryResult.warnings->slice())); } result->ForceSet(TRI_V8_ASCII_STRING("cached"), v8::Boolean::New(isolate, queryResult.cached));