diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 5dcad50eb1..ac461c4dad 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -32,6 +32,9 @@ #include "Basics/tri-strings.h" #include "VocBase/collection.h" +#include +#include + using namespace arangodb::aql; //////////////////////////////////////////////////////////////////////////////// @@ -1413,7 +1416,7 @@ AstNode* Ast::createNodeNaryOperator(AstNodeType type, AstNode const* child) { //////////////////////////////////////////////////////////////////////////////// void Ast::injectBindParameters(BindParameters& parameters) { - auto p = parameters(); + auto& p = parameters.get(); auto func = [&](AstNode* node, void*) -> AstNode* { if (node->type == NODE_TYPE_PARAMETER) { @@ -1425,7 +1428,7 @@ void Ast::injectBindParameters(BindParameters& parameters) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } - auto it = p.find(std::string(param, length)); + auto const& it = p.find(std::string(param, length)); if (it == p.end()) { // query uses a bind parameter that was not defined by the user @@ -1436,11 +1439,11 @@ void Ast::injectBindParameters(BindParameters& parameters) { // mark the bind parameter as being used (*it).second.second = true; - auto value = (*it).second.first; + auto& value = (*it).second.first; if (*param == '@') { // collection parameter - TRI_ASSERT(TRI_IsStringJson(value)); + TRI_ASSERT(value.isString()); // check if the collection was used in a data-modification query bool isWriteCollection = false; @@ -1454,9 +1457,11 @@ void Ast::injectBindParameters(BindParameters& parameters) { } // turn node into a collection node - size_t const length = value->_value._string.length - 1; + VPackValueLength length; + char const* stringValue = value.getString(length); + // TODO: can we get away without registering the string value here? char const* name = - _query->registerString(value->_value._string.data, length); + _query->registerString(stringValue, static_cast(length)); node = createNodeCollection(name, isWriteCollection ? TRI_TRANSACTION_WRITE @@ -1474,7 +1479,7 @@ void Ast::injectBindParameters(BindParameters& parameters) { } } } else { - node = nodeFromJson(value, false); + node = nodeFromVPack(value, false); if (node != nullptr) { // already mark node as constant here @@ -3005,6 +3010,70 @@ AstNode* Ast::nodeFromJson(TRI_json_t const* json, bool copyStringValues) { return createNodeValueNull(); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief create an AST node from vpack +/// if copyStringValues is `true`, then string values will be copied and will +/// be freed with the query afterwards. when set to `false`, string values +/// will not be copied and not freed by the query. the caller needs to make +/// sure then that string values are valid through the query lifetime. +//////////////////////////////////////////////////////////////////////////////// + +AstNode* Ast::nodeFromVPack(VPackSlice const& slice, bool copyStringValues) { + if (slice.isBoolean()) { + return createNodeValueBool(slice.getBoolean()); + } + + if (slice.isNumber()) { + return createNodeValueDouble(slice.getNumber()); + } + + if (slice.isString()) { + VPackValueLength length; + char const* p = slice.getString(length); + + if (copyStringValues) { + // we must copy string values! + p = _query->registerString(p, static_cast(length)); + } + // we can get away without copying string values + return createNodeValueString(p, length); + } + + if (slice.isArray()) { + auto node = createNodeArray(); + node->members.reserve(slice.length()); + + for (auto const& it : VPackArrayIterator(slice)) { + node->addMember(nodeFromVPack(it, copyStringValues)); + } + + return node; + } + + if (slice.isObject()) { + auto node = createNodeObject(); + node->members.reserve(slice.length()); + + for (auto const& it : VPackObjectIterator(slice)) { + VPackValueLength nameLength; + char const* attributeName = it.key.getString(nameLength); + + if (copyStringValues) { + // create a copy of the string value + attributeName = + _query->registerString(attributeName, static_cast(nameLength)); + } + + node->addMember(createNodeObjectElement( + attributeName, nameLength, nodeFromVPack(it.value, copyStringValues))); + } + + return node; + } + + return createNodeValueNull(); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST, using pre- and post-order visitors //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Ast.h b/arangod/Aql/Ast.h index fafcd4a8b2..2fe5d17551 100644 --- a/arangod/Aql/Ast.h +++ b/arangod/Aql/Ast.h @@ -36,6 +36,10 @@ #include namespace arangodb { +namespace velocypack { +class Slice; +} + namespace aql { class Query; @@ -674,6 +678,12 @@ class Ast { ////////////////////////////////////////////////////////////////////////////// AstNode* nodeFromJson(TRI_json_t const*, bool); + + ////////////////////////////////////////////////////////////////////////////// + /// @brief create an AST node from vpack + ////////////////////////////////////////////////////////////////////////////// + + AstNode* nodeFromVPack(arangodb::velocypack::Slice const&, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST using a depth-first visitor diff --git a/arangod/Aql/BindParameters.cpp b/arangod/Aql/BindParameters.cpp index dd996143d1..2857a8d441 100644 --- a/arangod/Aql/BindParameters.cpp +++ b/arangod/Aql/BindParameters.cpp @@ -33,34 +33,16 @@ #include using namespace arangodb::aql; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief create the parameters -//////////////////////////////////////////////////////////////////////////////// - -BindParameters::BindParameters(TRI_json_t* json) - : _json(json), _parameters(), _processed(false) {} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief destroy the parameters -//////////////////////////////////////////////////////////////////////////////// - -BindParameters::~BindParameters() { - if (_json != nullptr) { - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _json); - } -} - + //////////////////////////////////////////////////////////////////////////////// /// @brief create a hash value for the bind parameters //////////////////////////////////////////////////////////////////////////////// uint64_t BindParameters::hash() const { - if (_json == nullptr) { - return 0x12345678abcdef; + if (_builder == nullptr) { + return 0xdeadbeef; } - - return TRI_FastHashJson(_json); + return _builder->slice().hash(); } //////////////////////////////////////////////////////////////////////////////// @@ -68,43 +50,35 @@ uint64_t BindParameters::hash() const { //////////////////////////////////////////////////////////////////////////////// void BindParameters::process() { - if (_processed || _json == nullptr) { + if (_processed || _builder == nullptr) { return; } - if (!TRI_IsObjectJson(_json)) { + VPackSlice const slice = _builder->slice(); + if (slice.isNone()) { + return; + } + + if (!slice.isObject()) { THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_BIND_PARAMETERS_INVALID); } - size_t const n = TRI_LengthVector(&_json->_value._objects); - - for (size_t i = 0; i < n; i += 2) { - auto key = static_cast( - TRI_AddressVector(&_json->_value._objects, i)); - - if (!TRI_IsStringJson(key)) { - // no string, should not happen - THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE); - } - - std::string const k(key->_value._string.data, - key->_value._string.length - 1); - - auto value = static_cast( - TRI_AtVector(&_json->_value._objects, i + 1)); - - if (value == nullptr) { + for (auto const& it : VPackObjectIterator(slice)) { + std::string const key(it.key.copyString()); + VPackSlice const value(it.value); + + if (value.isNone()) { THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, - k.c_str()); + key.c_str()); } - if (k[0] == '@' && !TRI_IsStringJson(value)) { + if (key[0] == '@' && !value.isString()) { // collection bind parameter THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, - k.c_str()); + key.c_str()); } - _parameters.emplace(std::move(k), std::make_pair(value, false)); + _parameters.emplace(std::move(key), std::make_pair(value, false)); } _processed = true; @@ -140,35 +114,3 @@ VPackBuilder BindParameters::StripCollectionNames(VPackSlice const& keys, return result; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief strip collection name prefixes from the parameters -/// the values must be a JSON array. the array is modified in place -//////////////////////////////////////////////////////////////////////////////// - -void BindParameters::StripCollectionNames(TRI_json_t* keys, - char const* collectionName) { - if (!TRI_IsArrayJson(keys)) { - return; - } - - size_t const n = TRI_LengthVectorJson(keys); - - for (size_t i = 0; i < n; ++i) { - auto key = - static_cast(TRI_AtVector(&keys->_value._objects, i)); - - if (TRI_IsStringJson(key)) { - auto s = key->_value._string.data; - auto p = strchr(s, '/'); - - if (p != nullptr && strncmp(s, collectionName, p - s) == 0) { - size_t pos = static_cast(p - s); - // key begins with collection name + '/', now strip it in place for - // further comparisons - memmove(s, p + 1, key->_value._string.length - 2 - pos); - key->_value._string.length -= static_cast(pos + 1); - key->_value._string.data[key->_value._string.length - 1] = '\0'; - } - } - } -} diff --git a/arangod/Aql/BindParameters.h b/arangod/Aql/BindParameters.h index 8b36375a3d..50e8814014 100644 --- a/arangod/Aql/BindParameters.h +++ b/arangod/Aql/BindParameters.h @@ -25,17 +25,15 @@ #define ARANGOD_AQL_BIND_PARAMETERS_H 1 #include "Basics/Common.h" -#include "Basics/json.h" + +#include +#include +#include namespace arangodb { -namespace velocypack { -class Builder; -class Slice; -} namespace aql { -typedef std::unordered_map> - BindParametersType; +typedef std::unordered_map> BindParametersType; class BindParameters { public: @@ -47,20 +45,21 @@ class BindParameters { /// @brief create the parameters ////////////////////////////////////////////////////////////////////////////// - explicit BindParameters(TRI_json_t*); + explicit BindParameters(std::shared_ptr builder) + : _builder(builder), _parameters(), _processed(false) {} ////////////////////////////////////////////////////////////////////////////// /// @brief destroy the parameters ////////////////////////////////////////////////////////////////////////////// - ~BindParameters(); + ~BindParameters() = default; public: ////////////////////////////////////////////////////////////////////////////// /// @brief return all parameters ////////////////////////////////////////////////////////////////////////////// - BindParametersType const& operator()() { + BindParametersType& get() { process(); return _parameters; } @@ -79,13 +78,6 @@ class BindParameters { static arangodb::velocypack::Builder StripCollectionNames( arangodb::velocypack::Slice const&, char const*); - ////////////////////////////////////////////////////////////////////////////// - /// @brief strip collection name prefixes from the parameters - /// the values must be a JSON array. the array is modified in place - ////////////////////////////////////////////////////////////////////////////// - - static void StripCollectionNames(TRI_json_t*, char const*); - private: ////////////////////////////////////////////////////////////////////////////// /// @brief process the parameters @@ -98,7 +90,7 @@ class BindParameters { /// @brief the parameter json ////////////////////////////////////////////////////////////////////////////// - TRI_json_t* _json; + std::shared_ptr _builder; ////////////////////////////////////////////////////////////////////////////// /// @brief pointer to collection parameters diff --git a/arangod/Aql/CollectBlock.cpp b/arangod/Aql/CollectBlock.cpp index 9243b4622b..a62ef6ea92 100644 --- a/arangod/Aql/CollectBlock.cpp +++ b/arangod/Aql/CollectBlock.cpp @@ -237,7 +237,7 @@ SortedCollectBlock::SortedCollectBlock(ExecutionEngine* engine, // iterate over all our variables if (en->_keepVariables.empty()) { - auto&& usedVariableIds = en->getVariableIdsUsedHere(); + auto usedVariableIds(en->getVariableIdsUsedHere()); for (auto const& vi : registerPlan) { if (vi.second.depth > 0 || en->getDepth() == 1) { diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index bc3454c4e9..0a95372339 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -666,14 +666,14 @@ AqlValue Expression::executeSimpleExpressionIndexedAccess( index, &myCollection2, trx, argv, startPos, vars, regs, false); if (indexResult.isNumber()) { - auto&& indexString = std::to_string(indexResult.toInt64()); + auto indexString(std::to_string(indexResult.toInt64())); auto j = result.extractObjectMember(trx, myCollection, indexString.c_str(), true, _buffer); indexResult.destroy(); result.destroy(); return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, j.steal())); } else if (indexResult.isString()) { - auto&& value = indexResult.toString(); + auto value(indexResult.toString()); indexResult.destroy(); auto j = result.extractObjectMember(trx, myCollection, value.c_str(), diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 919597daba..334f4bc3d6 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -45,6 +45,9 @@ #include "VocBase/vocbase.h" #include "VocBase/Graphs.h" +#include +#include + using namespace arangodb; using namespace arangodb::aql; using Json = arangodb::basics::Json; @@ -168,7 +171,7 @@ bool Query::DoDisableQueryTracking = false; Query::Query(arangodb::ApplicationV8* applicationV8, bool contextOwnedByExterior, TRI_vocbase_t* vocbase, char const* queryString, size_t queryLength, - TRI_json_t* bindParameters, TRI_json_t* options, QueryPart part) + std::shared_ptr bindParameters, TRI_json_t* options, QueryPart part) : _id(0), _applicationV8(applicationV8), _vocbase(vocbase), @@ -312,7 +315,7 @@ Query* Query::clone(QueryPart part, bool withPlan) { std::unique_ptr clone; clone.reset(new Query(_applicationV8, false, _vocbase, _queryString, - _queryLength, nullptr, options.get(), part)); + _queryLength, std::shared_ptr(), options.get(), part)); options.release(); if (_plan != nullptr) { diff --git a/arangod/Aql/Query.h b/arangod/Aql/Query.h index c2b19e43ce..fd7439fa4f 100644 --- a/arangod/Aql/Query.h +++ b/arangod/Aql/Query.h @@ -114,7 +114,7 @@ class Query { public: Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, char const*, size_t, - struct TRI_json_t*, struct TRI_json_t*, QueryPart); + std::shared_ptr, struct TRI_json_t*, QueryPart); Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, arangodb::basics::Json queryStruct, struct TRI_json_t*, QueryPart); diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index 0cf25eb404..31df66ba29 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -157,7 +157,7 @@ void RestAqlHandler::parseQuery() { } auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), - queryString.size(), nullptr, nullptr, PART_MAIN); + queryString.size(), std::shared_ptr(), nullptr, PART_MAIN); QueryResult res = query->parse(); if (res.code != TRI_ERROR_NO_ERROR) { LOG(ERR) << "failed to instantiate the Query: " << res.details; @@ -212,14 +212,22 @@ void RestAqlHandler::explainQuery() { return; } - arangodb::basics::Json parameters; - parameters = queryJson.get("parameters").copy(); // cannot throw + auto bindVars = std::make_shared(); + { + int res = arangodb::basics::JsonHelper::toVelocyPack(queryJson.get("parameters").json(), *(bindVars.get())); + + if (res != TRI_ERROR_NO_ERROR) { + generateError(HttpResponse::BAD, TRI_ERROR_INTERNAL, + "could not convert parameters to vpack"); + return; + } + } + arangodb::basics::Json options; options = queryJson.get("options").copy(); // cannot throw auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), - queryString.size(), parameters.steal(), - options.steal(), PART_MAIN); + queryString.size(), bindVars, options.steal(), PART_MAIN); QueryResult res = query->explain(); if (res.code != TRI_ERROR_NO_ERROR) { LOG(ERR) << "failed to instantiate the Query: " << res.details; @@ -277,14 +285,23 @@ void RestAqlHandler::createQueryFromString() { return; } - arangodb::basics::Json parameters; - parameters = queryJson.get("parameters").copy(); // cannot throw + auto bindVars = std::make_shared(); + { + int res = arangodb::basics::JsonHelper::toVelocyPack(queryJson.get("parameters").json(), *(bindVars.get())); + + if (res != TRI_ERROR_NO_ERROR) { + generateError(HttpResponse::BAD, TRI_ERROR_INTERNAL, + "could not convert parameters to vpack"); + return; + } + } + arangodb::basics::Json options; options = queryJson.get("options").copy(); // cannot throw auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), - queryString.size(), parameters.steal(), options.steal(), + queryString.size(), bindVars, options.steal(), (part == "main" ? PART_MAIN : PART_DEPENDENT)); QueryResult res = query->prepare(_queryRegistry); if (res.code != TRI_ERROR_NO_ERROR) { diff --git a/arangod/RestHandler/RestCursorHandler.cpp b/arangod/RestHandler/RestCursorHandler.cpp index 70e1095042..bc956ecb21 100644 --- a/arangod/RestHandler/RestCursorHandler.cpp +++ b/arangod/RestHandler/RestCursorHandler.cpp @@ -101,6 +101,12 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { return; } } + + std::shared_ptr bindVarsBuilder; + if (!bindVars.isNone()) { + bindVarsBuilder.reset(new VPackBuilder); + bindVarsBuilder->add(bindVars); + } VPackBuilder optionsBuilder = buildOptions(slice); VPackSlice options = optionsBuilder.slice(); @@ -109,9 +115,7 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { arangodb::aql::Query query( _applicationV8, false, _vocbase, queryString, static_cast(l), - (!bindVars.isNone() - ? arangodb::basics::VelocyPackHelper::velocyPackToJson(bindVars) - : nullptr), + bindVarsBuilder, arangodb::basics::VelocyPackHelper::velocyPackToJson(options), arangodb::aql::PART_MAIN); diff --git a/arangod/RestHandler/RestSimpleHandler.cpp b/arangod/RestHandler/RestSimpleHandler.cpp index a3a436aee4..2c40b1b4f8 100644 --- a/arangod/RestHandler/RestSimpleHandler.cpp +++ b/arangod/RestHandler/RestSimpleHandler.cpp @@ -191,12 +191,11 @@ void RestSimpleHandler::removeByKeys(VPackSlice const& slice) { } } - VPackBuilder bindVars; - bindVars.openObject(); - bindVars.add("@collection", VPackValue(collectionName)); - bindVars.add("keys", keys); - bindVars.close(); - VPackSlice varsSlice = bindVars.slice(); + auto bindVars = std::make_shared(); + bindVars->openObject(); + bindVars->add("@collection", VPackValue(collectionName)); + bindVars->add("keys", keys); + bindVars->close(); std::string aql( "FOR key IN @keys REMOVE key IN @@collection OPTIONS { ignoreErrors: " @@ -206,8 +205,7 @@ void RestSimpleHandler::removeByKeys(VPackSlice const& slice) { arangodb::aql::Query query( _applicationV8, false, _vocbase, aql.c_str(), aql.size(), - arangodb::basics::VelocyPackHelper::velocyPackToJson(varsSlice), - nullptr, arangodb::aql::PART_MAIN); + bindVars, nullptr, arangodb::aql::PART_MAIN); registerQuery(&query); auto queryResult = query.execute(_queryRegistry); @@ -304,25 +302,22 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) { return; } - VPackBuilder bindVars; - bindVars.add(VPackValue(VPackValueType::Object)); - bindVars.add("@collection", VPackValue(collectionName)); + auto bindVars = std::make_shared(); + bindVars->openObject(); + bindVars->add("@collection", VPackValue(collectionName)); VPackBuilder strippedBuilder = arangodb::aql::BindParameters::StripCollectionNames( keys, collectionName.c_str()); - VPackSlice stripped = strippedBuilder.slice(); - bindVars.add("keys", stripped); - bindVars.close(); - VPackSlice varsSlice = bindVars.slice(); + bindVars->add("keys", strippedBuilder.slice()); + bindVars->close(); std::string const aql( "FOR doc IN @@collection FILTER doc._key IN @keys RETURN doc"); arangodb::aql::Query query( _applicationV8, false, _vocbase, aql.c_str(), aql.size(), - arangodb::basics::VelocyPackHelper::velocyPackToJson(varsSlice), - nullptr, arangodb::aql::PART_MAIN); + bindVars, nullptr, arangodb::aql::PART_MAIN); registerQuery(&query); auto queryResult = query.execute(_queryRegistry); diff --git a/arangod/Scheduler/Scheduler.cpp b/arangod/Scheduler/Scheduler.cpp index 526d654b84..0ac9dad25d 100644 --- a/arangod/Scheduler/Scheduler.cpp +++ b/arangod/Scheduler/Scheduler.cpp @@ -401,7 +401,7 @@ void Scheduler::setProcessorAffinity(size_t i, size_t c) { Task* Scheduler::lookupTaskById(uint64_t taskId) { MUTEX_LOCKER(mutexLocker, schedulerLock); - auto&& task = taskRegistered.find(taskId); + auto task = taskRegistered.find(taskId); if (task == taskRegistered.end()) { return nullptr; @@ -417,7 +417,7 @@ Task* Scheduler::lookupTaskById(uint64_t taskId) { EventLoop Scheduler::lookupLoopById(uint64_t taskId) { MUTEX_LOCKER(mutexLocker, schedulerLock); - auto&& task = taskRegistered.find(taskId); + auto task = taskRegistered.find(taskId); if (task == taskRegistered.end()) { return static_cast(nrThreads); diff --git a/arangod/V8Server/v8-actions.cpp b/arangod/V8Server/v8-actions.cpp index 220bac9b18..1c6a2f7413 100644 --- a/arangod/V8Server/v8-actions.cpp +++ b/arangod/V8Server/v8-actions.cpp @@ -360,7 +360,7 @@ static v8::Handle RequestCppToV8(v8::Isolate* isolate, req->ForceSet(ProtocolKey, TRI_V8_STD_STRING(protocol)); // set the task id - std::string const&& taskId = StringUtils::itoa(request->clientTaskId()); + std::string const taskId(StringUtils::itoa(request->clientTaskId())); // set the connection info const ConnectionInfo& info = request->connectionInfo(); @@ -590,8 +590,7 @@ static HttpResponse* ResponseV8ToCpp(v8::Isolate* isolate, response->body().appendText(V8Buffer::data(obj), V8Buffer::length(obj)); } else { // treat body as a string - std::string&& obj(TRI_ObjectToString(res->Get(BodyKey))); - response->body().appendText(obj); + response->body().appendText(TRI_ObjectToString(res->Get(BodyKey))); } } } diff --git a/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp index 0251846f50..da71bf62e1 100644 --- a/arangod/V8Server/v8-query.cpp +++ b/arangod/V8Server/v8-query.cpp @@ -49,6 +49,7 @@ #include "VocBase/vocbase.h" #include "VocBase/VocShaper.h" +#include #include #include #include @@ -61,21 +62,12 @@ using namespace arangodb::basics; //////////////////////////////////////////////////////////////////////////////// static v8::Handle AqlQuery(v8::Isolate* isolate, TRI_vocbase_col_t const* col, - std::string const& aql, VPackSlice const& slice) { + std::string const& aql, std::shared_ptr bindVars) { TRI_ASSERT(col != nullptr); - arangodb::basics::Json bindVars(arangodb::basics::Json::Object, 2); - - VPackObjectIterator it(slice); - while (it.valid()) { - bindVars(it.key().copyString().c_str(), arangodb::basics::Json(TRI_UNKNOWN_MEM_ZONE, VelocyPackHelper::velocyPackToJson(it.value()))); - it.next(); - } - - TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, col->_vocbase, - aql.c_str(), aql.size(), bindVars.steal(), nullptr, + aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.executeV8( @@ -542,17 +534,17 @@ static void EdgesQuery(TRI_edge_direction_e direction, TRI_THROW_SHARDING_COLLECTION_NOT_YET_IMPLEMENTED(col); - VPackBuilder builder; - builder.openObject(); - builder.add("@collection", VPackValue(col->name())); - builder.add(VPackValue("value")); - int res = TRI_V8ToVPack(isolate, builder, args[0], false); + auto bindVars = std::make_shared(); + bindVars->openObject(); + bindVars->add("@collection", VPackValue(col->name())); + bindVars->add(VPackValue("value")); + int res = TRI_V8ToVPack(isolate, *(bindVars.get()), args[0], false); + bindVars->close(); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION(res); } - builder.close(); std::string filter; // argument is a list of vertices @@ -577,7 +569,7 @@ static void EdgesQuery(TRI_edge_direction_e direction, } trx.lockRead(); - v8::Handle result = AqlQuery(isolate, col, "FOR doc IN @@collection " + filter + " RETURN doc", builder.slice()); + v8::Handle result = AqlQuery(isolate, col, "FOR doc IN @@collection " + filter + " RETURN doc", bindVars); trx.finish(res); TRI_V8_RETURN(result); @@ -1287,7 +1279,7 @@ static void FulltextQuery(SingleCollectionTransaction& trx, TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_NO_INDEX); } - std::string const&& queryString = TRI_ObjectToString(args[1]); + std::string queryString(TRI_ObjectToString(args[1])); bool isSubstringQuery = false; size_t maxResults = 0; // 0 means "all results" @@ -1628,22 +1620,29 @@ static void JS_LookupByKeys(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION_USAGE("documents()"); } - arangodb::basics::Json bindVars(arangodb::basics::Json::Object, 2); - bindVars("@collection", arangodb::basics::Json(std::string(col->_name))); - bindVars("keys", arangodb::basics::Json(TRI_UNKNOWN_MEM_ZONE, - TRI_ObjectToJson(isolate, args[0]))); + auto bindVars = std::make_shared(); + bindVars->openObject(); + bindVars->add("@collection", VPackValue(std::string(col->_name))); - std::string const collectionName(col->name()); + VPackBuilder keys; + int res = TRI_V8ToVPack(isolate, keys, args[0], false); - arangodb::aql::BindParameters::StripCollectionNames( - TRI_LookupObjectJson(bindVars.json(), "keys"), collectionName.c_str()); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } + + VPackBuilder strippedBuilder = + arangodb::aql::BindParameters::StripCollectionNames(keys.slice(), col->_name.c_str()); + + bindVars->add("keys", strippedBuilder.slice()); + bindVars->close(); std::string const aql( "FOR doc IN @@collection FILTER doc._key IN @keys RETURN doc"); TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, col->_vocbase, - aql.c_str(), aql.size(), bindVars.steal(), nullptr, + aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.executeV8( @@ -1684,10 +1683,16 @@ static void JS_RemoveByKeys(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION_USAGE("removeByKeys()"); } - arangodb::basics::Json bindVars(arangodb::basics::Json::Object, 2); - bindVars("@collection", arangodb::basics::Json(std::string(col->_name))); - bindVars("keys", arangodb::basics::Json(TRI_UNKNOWN_MEM_ZONE, - TRI_ObjectToJson(isolate, args[0]))); + auto bindVars = std::make_shared(); + bindVars->openObject(); + bindVars->add("@collection", VPackValue(col->_name)); + bindVars->add(VPackValue("keys")); + + int res = TRI_V8ToVPack(isolate, *(bindVars.get()), args[0], false); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } + bindVars->close(); std::string const aql( "FOR key IN @keys REMOVE key IN @@collection OPTIONS { ignoreErrors: " @@ -1695,7 +1700,7 @@ static void JS_RemoveByKeys(v8::FunctionCallbackInfo const& args) { TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, col->_vocbase, - aql.c_str(), aql.size(), bindVars.steal(), nullptr, + aql.c_str(), aql.size(), bindVars, nullptr, arangodb::aql::PART_MAIN); auto queryResult = query.executeV8( diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index e47c952f92..b3e1d696a1 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1098,17 +1098,23 @@ static void JS_ExplainAql(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting string for "); } - std::string const&& queryString = TRI_ObjectToString(args[0]); + std::string const queryString(TRI_ObjectToString(args[0])); // bind parameters - std::unique_ptr parameters; + std::shared_ptr bindVars; if (args.Length() > 1) { if (!args[1]->IsUndefined() && !args[1]->IsNull() && !args[1]->IsObject()) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } if (args[1]->IsObject()) { - parameters.reset(TRI_ObjectToJson(isolate, args[1])); + bindVars.reset(new VPackBuilder); + + int res = TRI_V8ToVPack(isolate, *(bindVars.get()), args[1], false); + + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } } } @@ -1127,7 +1133,7 @@ static void JS_ExplainAql(v8::FunctionCallbackInfo const& args) { TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), - parameters.release(), options.release(), + bindVars, options.release(), arangodb::aql::PART_MAIN); auto queryResult = query.explain(); @@ -1277,10 +1283,10 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting string for "); } - std::string const&& queryString = TRI_ObjectToString(args[0]); + std::string const queryString(TRI_ObjectToString(args[0])); // bind parameters - std::unique_ptr parameters; + std::shared_ptr bindVars; // options std::unique_ptr options; @@ -1290,7 +1296,12 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } if (args[1]->IsObject()) { - parameters.reset(TRI_ObjectToJson(isolate, args[1])); + bindVars.reset(new VPackBuilder); + int res = TRI_V8ToVPack(isolate, *(bindVars.get()), args[1], false); + + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } } } @@ -1307,11 +1318,10 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), - parameters.get(), options.get(), + bindVars, options.get(), arangodb::aql::PART_MAIN); options.release(); - parameters.release(); auto queryResult = query.executeV8( isolate, static_cast(v8g->_queryRegistry)); diff --git a/arangod/V8Server/v8-vocindex.cpp b/arangod/V8Server/v8-vocindex.cpp index 70dbea3eb2..8b4abd5924 100644 --- a/arangod/V8Server/v8-vocindex.cpp +++ b/arangod/V8Server/v8-vocindex.cpp @@ -1308,7 +1308,7 @@ static void JS_GetIndexesVocbaseCol( std::string const& collectionName = std::string(collection->_name); // get list of indexes - auto&& indexes = TRI_IndexesDocumentCollection(document, withFigures); + auto indexes(TRI_IndexesDocumentCollection(document, withFigures)); trx.finish(res); // READ-LOCK end diff --git a/arangod/VocBase/collection.h b/arangod/VocBase/collection.h index f326fc8689..ea5d5cdd6f 100644 --- a/arangod/VocBase/collection.h +++ b/arangod/VocBase/collection.h @@ -50,8 +50,6 @@ /// concrete sub-class @ref TRI_document_collection_t. //////////////////////////////////////////////////////////////////////////////// -struct TRI_json_t; - namespace arangodb { class CollectionInfo; namespace velocypack {