diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index 11d0b97fc4..64881ef966 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -534,7 +534,9 @@ AstNode::AstNode(Ast* ast, arangodb::basics::Json const& json) break; } case NODE_TYPE_VARIABLE: { - auto variable = ast->variables()->createVariable(json); +#warning Fix this + auto builder = JsonHelper::toVelocyPack(json.json()); + auto variable = ast->variables()->createVariable(builder->slice()); TRI_ASSERT(variable != nullptr); setData(variable); break; diff --git a/arangod/Aql/ExecutionNode.cpp b/arangod/Aql/ExecutionNode.cpp index 7b88e63816..d3a65eee36 100644 --- a/arangod/Aql/ExecutionNode.cpp +++ b/arangod/Aql/ExecutionNode.cpp @@ -377,7 +377,9 @@ ExecutionNode::ExecutionNode(ExecutionPlan* plan, len = jsonvarsUsedLater.size(); _varsUsedLater.reserve(len); for (size_t i = 0; i < len; i++) { - auto oneVarUsedLater = std::make_unique(jsonvarsUsedLater.at(i)); +#warning Still Json Version. Ignore return val + auto builder = JsonHelper::toVelocyPack(jsonvarsUsedLater.at(i).json()); + auto oneVarUsedLater = std::make_unique(builder->slice()); Variable* oneVariable = allVars->getVariable(oneVarUsedLater->id); if (oneVariable == nullptr) { @@ -398,7 +400,9 @@ ExecutionNode::ExecutionNode(ExecutionPlan* plan, len = jsonvarsValidList.size(); _varsValid.reserve(len); for (size_t i = 0; i < len; i++) { - auto oneVarValid = std::make_unique(jsonvarsValidList.at(i)); +#warning Deprecated + auto builder = JsonHelper::toVelocyPack(jsonvarsValidList.at(i).json()); + auto oneVarValid = std::make_unique(builder->slice()); Variable* oneVariable = allVars->getVariable(oneVarValid->id); if (oneVariable == nullptr) { @@ -629,8 +633,9 @@ Variable* ExecutionNode::varFromJson(Ast* ast, "Mandatory variable \"" + std::string(variableName) + "\" not found."; THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, msg.c_str()); } - - return ast->variables()->createVariable(variableJson); +#warning Deprecated + auto builder = JsonHelper::toVelocyPack(variableJson.json()); + return ast->variables()->createVariable(builder->slice()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index 63e0260839..705b32d060 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -42,6 +42,9 @@ #include "Basics/tri-strings.h" #include "Basics/VelocyPackHelper.h" +#include +#include + using namespace arangodb::aql; using namespace arangodb::basics; @@ -97,48 +100,47 @@ ExecutionPlan* ExecutionPlan::instantiateFromAst(Ast* ast) { } //////////////////////////////////////////////////////////////////////////////// -/// @brief process the list of collections in a JSON +/// @brief process the list of collections in a VelocyPack //////////////////////////////////////////////////////////////////////////////// -void ExecutionPlan::getCollectionsFromJson(Ast* ast, - arangodb::basics::Json const& json) { +void ExecutionPlan::getCollectionsFromVelocyPack(Ast* ast, + VPackSlice const slice) { TRI_ASSERT(ast != nullptr); - arangodb::basics::Json jsonCollections = json.get("collections"); + VPackSlice collectionsSlice = slice.get("collections"); - if (!jsonCollections.isArray()) { + if (!collectionsSlice.isArray()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_INTERNAL, "json node \"collections\" not found or not an array"); } - auto const size = jsonCollections.size(); - - for (size_t i = 0; i < size; i++) { - arangodb::basics::Json oneJsonCollection = - jsonCollections.at(static_cast(i)); - auto typeStr = arangodb::basics::JsonHelper::checkAndGetStringValue( - oneJsonCollection.json(), "type"); - + for (auto const& collection : VPackArrayIterator(collectionsSlice)) { + auto typeStr = arangodb::basics::VelocyPackHelper::checkAndGetStringValue( + collection, "type"); ast->query()->collections()->add( - arangodb::basics::JsonHelper::checkAndGetStringValue( - oneJsonCollection.json(), "name"), + arangodb::basics::VelocyPackHelper::checkAndGetStringValue(collection, + "name"), TRI_GetTransactionTypeFromStr( - arangodb::basics::JsonHelper::checkAndGetStringValue( - oneJsonCollection.json(), "type").c_str())); + arangodb::basics::VelocyPackHelper::checkAndGetStringValue( + collection, "type") + .c_str())); } } //////////////////////////////////////////////////////////////////////////////// -/// @brief create an execution plan from JSON +/// @brief create an execution plan from VelocyPack //////////////////////////////////////////////////////////////////////////////// -ExecutionPlan* ExecutionPlan::instantiateFromJson( - Ast* ast, arangodb::basics::Json const& json) { +ExecutionPlan* ExecutionPlan::instantiateFromVelocyPack( + Ast* ast, VPackSlice const slice) { TRI_ASSERT(ast != nullptr); auto plan = std::make_unique(ast); +#warning In place slice => Json + Json json(TRI_UNKNOWN_MEM_ZONE, + arangodb::basics::VelocyPackHelper::velocyPackToJson(slice)); plan->_root = plan->fromJson(json); plan->_varUsageComputed = true; diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index 0774bc23fa..038483a1c0 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -63,18 +63,18 @@ class ExecutionPlan { static ExecutionPlan* instantiateFromAst(Ast*); ////////////////////////////////////////////////////////////////////////////// - /// @brief process the list of collections in a JSON + /// @brief process the list of collections in a VelocyPack ////////////////////////////////////////////////////////////////////////////// - static void getCollectionsFromJson(Ast* ast, - arangodb::basics::Json const& Json); + static void getCollectionsFromVelocyPack(Ast* ast, + arangodb::velocypack::Slice const); ////////////////////////////////////////////////////////////////////////////// - /// @brief create an execution plan from JSON + /// @brief create an execution plan from VelocyPack ////////////////////////////////////////////////////////////////////////////// - static ExecutionPlan* instantiateFromJson(Ast* ast, - arangodb::basics::Json const& Json); + static ExecutionPlan* instantiateFromVelocyPack( + Ast* ast, arangodb::velocypack::Slice const); ////////////////////////////////////////////////////////////////////////////// /// @brief clone the plan by recursively cloning starting from the root diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index f437379627..8a8291ef0f 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -47,6 +47,7 @@ #include "VocBase/Graphs.h" #include +#include #include using namespace arangodb; @@ -146,19 +147,6 @@ std::shared_ptr Profile::toVelocyPack() { return result; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief convert the profile to JSON -//////////////////////////////////////////////////////////////////////////////// - -TRI_json_t* Profile::toJson(TRI_memory_zone_t*) { - arangodb::basics::Json result(arangodb::basics::Json::Object); - for (auto const& it : results) { - result.set(StateNames[static_cast(it.first)].c_str(), - arangodb::basics::Json(it.second)); - } - return result.steal(); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not query tracking is disabled globally //////////////////////////////////////////////////////////////////////////////// @@ -172,7 +160,7 @@ bool Query::DoDisableQueryTracking = false; Query::Query(arangodb::ApplicationV8* applicationV8, bool contextOwnedByExterior, TRI_vocbase_t* vocbase, char const* queryString, size_t queryLength, - std::shared_ptr bindParameters, VPackSlice const options, QueryPart part) + std::shared_ptr const bindParameters, std::shared_ptr const options, QueryPart part) : _id(0), _applicationV8(applicationV8), _vocbase(vocbase), @@ -180,9 +168,9 @@ Query::Query(arangodb::ApplicationV8* applicationV8, _context(nullptr), _queryString(queryString), _queryLength(queryLength), - _queryJson(), + _queryBuilder(), _bindParameters(bindParameters), - _options(arangodb::basics::VelocyPackHelper::velocyPackToJson(options)), + _options(options), _collections(vocbase), _strings(), _shortStringStorage(1024), @@ -205,98 +193,14 @@ Query::Query(arangodb::ApplicationV8* applicationV8, TRI_ASSERT(_vocbase != nullptr); } - - -//////////////////////////////////////////////////////////////////////////////// -/// @brief creates a query -//////////////////////////////////////////////////////////////////////////////// - -Query::Query(arangodb::ApplicationV8* applicationV8, - bool contextOwnedByExterior, TRI_vocbase_t* vocbase, - char const* queryString, size_t queryLength, - std::shared_ptr bindParameters, TRI_json_t* options, QueryPart part) - : _id(0), - _applicationV8(applicationV8), - _vocbase(vocbase), - _executor(nullptr), - _context(nullptr), - _queryString(queryString), - _queryLength(queryLength), - _queryJson(), - _bindParameters(bindParameters), - _options(options), - _collections(vocbase), - _strings(), - _shortStringStorage(1024), - _ast(nullptr), - _profile(nullptr), - _state(INVALID_STATE), - _plan(nullptr), - _parser(nullptr), - _trx(nullptr), - _engine(nullptr), - _maxWarningCount(10), - _warnings(), - _startTime(TRI_microtime()), - _part(part), - _contextOwnedByExterior(contextOwnedByExterior), - _killed(false), - _isModificationQuery(false) { - // std::cout << TRI_CurrentThreadId() << ", QUERY " << this << " CTOR: " << - // queryString << "\n"; - - TRI_ASSERT(_vocbase != nullptr); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief creates a query from Json -//////////////////////////////////////////////////////////////////////////////// - -Query::Query(arangodb::ApplicationV8* applicationV8, - bool contextOwnedByExterior, TRI_vocbase_t* vocbase, - arangodb::basics::Json queryStruct, TRI_json_t* options, - QueryPart part) - : _id(0), - _applicationV8(applicationV8), - _vocbase(vocbase), - _executor(nullptr), - _context(nullptr), - _queryString(nullptr), - _queryLength(0), - _queryJson(queryStruct), - _bindParameters(nullptr), - _options(options), - _collections(vocbase), - _strings(), - _shortStringStorage(1024), - _ast(nullptr), - _profile(nullptr), - _state(INVALID_STATE), - _plan(nullptr), - _parser(nullptr), - _trx(nullptr), - _engine(nullptr), - _maxWarningCount(10), - _warnings(), - _startTime(TRI_microtime()), - _part(part), - _contextOwnedByExterior(contextOwnedByExterior), - _killed(false), - _isModificationQuery(false) { - // std::cout << TRI_CurrentThreadId() << ", QUERY " << this << " CTOR (JSON): - // " << _queryJson.toString() << "\n"; - - TRI_ASSERT(_vocbase != nullptr); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief creates a query from VelocyPack //////////////////////////////////////////////////////////////////////////////// Query::Query(arangodb::ApplicationV8* applicationV8, bool contextOwnedByExterior, TRI_vocbase_t* vocbase, - std::shared_ptr queryStruct, - VPackSlice const options, QueryPart part) + std::shared_ptr const queryStruct, + std::shared_ptr const options, QueryPart part) : _id(0), _applicationV8(applicationV8), _vocbase(vocbase), @@ -304,10 +208,9 @@ Query::Query(arangodb::ApplicationV8* applicationV8, _context(nullptr), _queryString(nullptr), _queryLength(0), - _queryJson(TRI_UNKNOWN_MEM_ZONE, arangodb::basics::VelocyPackHelper::velocyPackToJson( - queryStruct->slice())), + _queryBuilder(queryStruct), _bindParameters(nullptr), - _options(arangodb::basics::VelocyPackHelper::velocyPackToJson(options)), + _options(options), _collections(vocbase), _strings(), _shortStringStorage(1024), @@ -343,11 +246,6 @@ Query::~Query() { delete _profile; _profile = nullptr; - if (_options != nullptr) { - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _options); - _options = nullptr; - } - delete _executor; _executor = nullptr; @@ -390,21 +288,11 @@ Query::~Query() { //////////////////////////////////////////////////////////////////////////////// Query* Query::clone(QueryPart part, bool withPlan) { - std::unique_ptr options; - - if (_options != nullptr) { - options.reset(TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, _options)); - - if (options == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - } std::unique_ptr clone; clone.reset(new Query(_applicationV8, false, _vocbase, _queryString, - _queryLength, std::shared_ptr(), options.get(), part)); - options.release(); + _queryLength, std::shared_ptr(), _options, part)); if (_plan != nullptr) { if (withPlan) { @@ -618,11 +506,13 @@ QueryResult Query::prepare(QueryRegistry* registry) { // Now plan and all derived plans belong to the optimizer plan.reset(opt.stealBest()); // Now we own the best one again planRegisters = true; - } else { // no queryString, we are instantiating from _queryJson + } else { // no queryString, we are instantiating from _queryBuilder enterState(PLAN_INSTANTIATION); - ExecutionPlan::getCollectionsFromJson(parser->ast(), _queryJson); - parser->ast()->variables()->fromJson(_queryJson); + VPackSlice const querySlice = _queryBuilder->slice(); + ExecutionPlan::getCollectionsFromVelocyPack(parser->ast(), querySlice); + + parser->ast()->variables()->fromVelocyPack(querySlice); // creating the plan may have produced some collections // we need to add them to the transaction now (otherwise the query will // fail) @@ -637,8 +527,8 @@ QueryResult Query::prepare(QueryRegistry* registry) { return transactionError(res); } - // we have an execution plan in JSON format - plan.reset(ExecutionPlan::instantiateFromJson(parser->ast(), _queryJson)); + // we have an execution plan in VelocyPack format + plan.reset(ExecutionPlan::instantiateFromVelocyPack(parser->ast(), _queryBuilder->slice())); if (plan.get() == nullptr) { // oops return QueryResult(TRI_ERROR_INTERNAL); @@ -721,7 +611,12 @@ QueryResult Query::execute(QueryRegistry* registry) { if (cacheEntry != nullptr) { // got a result from the query cache QueryResult res(TRI_ERROR_NO_ERROR); - res.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE); +#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 = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, cacheEntry->_queryResult); res.cached = true; @@ -838,12 +733,17 @@ QueryResult Query::execute(QueryRegistry* registry) { enterState(FINALIZATION); QueryResult result(TRI_ERROR_NO_ERROR); - result.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE); +#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.stats = stats; if (_profile != nullptr && profiling()) { - result.profile = _profile->toJson(TRI_UNKNOWN_MEM_ZONE); + result.profile = _profile->toVelocyPack(); } return result; @@ -992,11 +892,16 @@ QueryResultV8 Query::executeV8(v8::Isolate* isolate, QueryRegistry* registry) { enterState(FINALIZATION); - result.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE); +#warning Replace QueryResult with VPack + VPackBuilder tmp; + tmp.openObject(); + warningsToVelocyPack(tmp); + tmp.close(); + result.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); result.stats = stats; if (_profile != nullptr && profiling()) { - result.profile = _profile->toJson(TRI_UNKNOWN_MEM_ZONE); + result.profile = _profile->toVelocyPack(); } return result; @@ -1130,7 +1035,13 @@ QueryResult Query::explain() { _trx->commit(); - result.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE); +#warning Replace QueryResult with VPack + VPackBuilder tmp; + tmp.openObject(); + warningsToVelocyPack(tmp); + tmp.close(); + result.warnings = arangodb::basics::VelocyPackHelper::velocyPackToJson(tmp.slice().get("warnings")); + result.stats = opt._stats.toVelocyPack(); return result; @@ -1308,16 +1219,17 @@ void Query::getStats(VPackBuilder& builder) { //////////////////////////////////////////////////////////////////////////////// bool Query::getBooleanOption(char const* option, bool defaultValue) const { - if (!TRI_IsObjectJson(_options)) { + VPackSlice options = _options->slice(); + if (!options.isObject()) { return defaultValue; } - TRI_json_t const* valueJson = TRI_LookupObjectJson(_options, option); - if (!TRI_IsBooleanJson(valueJson)) { + VPackSlice value = options.get(option); + if (!value.isBoolean()) { return defaultValue; } - return valueJson->_value._boolean; + return value.getBool(); } @@ -1327,43 +1239,21 @@ 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&) const { -#warning Needs to be implemented. - THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief convert the list of warnings to JSON -//////////////////////////////////////////////////////////////////////////////// - -TRI_json_t* Query::warningsToJson(TRI_memory_zone_t* zone) const { +void Query::warningsToVelocyPack(arangodb::velocypack::Builder& builder) const { + TRI_ASSERT(builder.isOpenObject()); if (_warnings.empty()) { - return nullptr; + return; } - size_t const n = _warnings.size(); - TRI_json_t* json = TRI_CreateArrayJson(zone, n); - - if (json != nullptr) { + builder.add(VPackValue("warnings")); + { + VPackArrayBuilder guard(&builder); for (size_t i = 0; i < n; ++i) { - TRI_json_t* error = TRI_CreateObjectJson(zone, 2); - - if (error != nullptr) { - TRI_Insert3ObjectJson( - zone, error, "code", - TRI_CreateNumberJson(zone, - static_cast(_warnings[i].first))); - TRI_Insert3ObjectJson( - zone, error, "message", - TRI_CreateStringCopyJson(zone, _warnings[i].second.c_str(), - _warnings[i].second.size())); - - TRI_PushBack3ArrayJson(zone, json, error); - } + VPackObjectBuilder objGuard(&builder); + builder.add("code", VPackValue(_warnings[i].first)); + builder.add("message", VPackValue(_warnings[i].second)); } } - - return json; } //////////////////////////////////////////////////////////////////////////////// @@ -1470,16 +1360,17 @@ bool Query::canUseQueryCache() const { //////////////////////////////////////////////////////////////////////////////// double Query::getNumericOption(char const* option, double defaultValue) const { - if (!TRI_IsObjectJson(_options)) { + VPackSlice options = _options->slice(); + if (!options.isObject()) { return defaultValue; } - TRI_json_t const* valueJson = TRI_LookupObjectJson(_options, option); - if (!TRI_IsNumberJson(valueJson)) { + VPackSlice value = options.get(option); + if (!value.isNumber()) { return defaultValue; } - return valueJson->_value._number; + return value.getNumericValue(); } //////////////////////////////////////////////////////////////////////////////// @@ -1507,21 +1398,19 @@ QueryResult Query::transactionError(int errorCode) const { //////////////////////////////////////////////////////////////////////////////// bool Query::inspectSimplePlans() const { - if (!TRI_IsObjectJson(_options)) { + VPackSlice options = _options->slice(); + if (!options.isObject()) { return true; // default } - TRI_json_t const* optJson = TRI_LookupObjectJson(_options, "optimizer"); + VPackSlice opt = options.get("optimizer"); - if (!TRI_IsObjectJson(optJson)) { + if (!opt.isObject()) { return true; // default } - TRI_json_t const* j = TRI_LookupObjectJson(optJson, "inspectSimplePlans"); - if (TRI_IsBooleanJson(j)) { - return j->_value._boolean; - } - return true; // default; + return arangodb::basics::VelocyPackHelper::getBooleanValue( + opt, "inspectSimplePlans", true); } //////////////////////////////////////////////////////////////////////////////// @@ -1531,31 +1420,27 @@ bool Query::inspectSimplePlans() const { std::vector Query::getRulesFromOptions() const { std::vector rules; - if (!TRI_IsObjectJson(_options)) { + VPackSlice options = _options->slice(); + + if (!options.isObject()){ return rules; } - TRI_json_t const* optJson = TRI_LookupObjectJson(_options, "optimizer"); + VPackSlice opt = options.get("optimizer"); - if (!TRI_IsObjectJson(optJson)) { + if (!opt.isObject()) { return rules; } - TRI_json_t const* rulesJson = TRI_LookupObjectJson(optJson, "rules"); + VPackSlice rulesList = opt.get("rules"); - if (!TRI_IsArrayJson(rulesJson)) { + if (!rulesList.isArray()) { return rules; } - size_t const n = TRI_LengthArrayJson(rulesJson); - - for (size_t i = 0; i < n; ++i) { - TRI_json_t const* rule = static_cast( - TRI_AtVector(&rulesJson->_value._objects, i)); - - if (TRI_IsStringJson(rule)) { - rules.emplace_back(rule->_value._string.data, - rule->_value._string.length - 1); + for (auto const& rule : VPackArrayIterator(rulesList)) { + if (rule.isString()){ + rules.emplace_back(rule.copyString()); } } diff --git a/arangod/Aql/Query.h b/arangod/Aql/Query.h index ff29644aa8..fd736ef4dd 100644 --- a/arangod/Aql/Query.h +++ b/arangod/Aql/Query.h @@ -38,7 +38,6 @@ #include -struct TRI_json_t; struct TRI_vocbase_t; namespace arangodb { @@ -97,8 +96,6 @@ struct Profile { std::shared_ptr toVelocyPack(); - TRI_json_t* toJson(TRI_memory_zone_t*); - Query* query; std::vector> results; double stamp; @@ -116,19 +113,12 @@ class Query { public: Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, char const*, size_t, - std::shared_ptr, struct TRI_json_t*, - QueryPart); - - Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, char const*, size_t, - std::shared_ptr, - arangodb::velocypack::Slice const, QueryPart); + std::shared_ptr const, + std::shared_ptr const, QueryPart); Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, - arangodb::basics::Json queryStruct, struct TRI_json_t*, QueryPart); - - Query(arangodb::ApplicationV8*, bool, TRI_vocbase_t*, - std::shared_ptr, - arangodb::velocypack::Slice const, QueryPart); + std::shared_ptr const, + std::shared_ptr const, QueryPart); ~Query(); @@ -407,12 +397,6 @@ class Query { bool getBooleanOption(char const*, bool) const; - ////////////////////////////////////////////////////////////////////////////// - /// @brief convert the list of warnings to JSON - ////////////////////////////////////////////////////////////////////////////// - - TRI_json_t* warningsToJson(TRI_memory_zone_t*) const; - ////////////////////////////////////////////////////////////////////////////// /// @brief convert the list of warnings to VelocyPack. /// Will add a new entry { ..., warnings: , } if there are @@ -582,10 +566,10 @@ class Query { size_t const _queryLength; ////////////////////////////////////////////////////////////////////////////// - /// @brief query in a JSON structure + /// @brief query in a VelocyPack structure ////////////////////////////////////////////////////////////////////////////// - arangodb::basics::Json const _queryJson; + std::shared_ptr const _queryBuilder; ////////////////////////////////////////////////////////////////////////////// /// @brief bind parameters for the query @@ -597,7 +581,7 @@ class Query { /// @brief query options ////////////////////////////////////////////////////////////////////////////// - TRI_json_t* _options; + std::shared_ptr _options; ////////////////////////////////////////////////////////////////////////////// /// @brief collections used in the query diff --git a/arangod/Aql/QueryResult.h b/arangod/Aql/QueryResult.h index 03b87c2127..783d765ade 100644 --- a/arangod/Aql/QueryResult.h +++ b/arangod/Aql/QueryResult.h @@ -77,9 +77,6 @@ struct QueryResult { if (json != nullptr) { TRI_FreeJson(zone, json); } - if (profile != nullptr) { - TRI_FreeJson(zone, profile); - } } int code; @@ -91,7 +88,7 @@ struct QueryResult { TRI_json_t* warnings; TRI_json_t* json; std::shared_ptr stats; - TRI_json_t* profile; + std::shared_ptr profile; TRI_json_t* clusterplan; }; } diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index c784fc381f..a227d56d8e 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -92,7 +92,8 @@ void RestAqlHandler::createQueryFromVelocyPack() { return; } - VPackSlice options = querySlice.get("options"); + auto options = std::make_shared( + VPackBuilder::clone(querySlice.get("options"))); std::string const part = VelocyPackHelper::getStringValue(querySlice, "part", ""); @@ -240,10 +241,9 @@ void RestAqlHandler::explainQuery() { return; } -#warning Can we use Builder::clone(Slice) here? auto bindVars = std::make_shared(VPackBuilder::clone(querySlice.get("parameters"))); - VPackSlice options = querySlice.get("options"); + auto options = std::make_shared(VPackBuilder::clone(querySlice.get("options"))); auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), queryString.size(), bindVars, options, PART_MAIN); @@ -314,9 +314,10 @@ void RestAqlHandler::createQueryFromString() { return; } - auto bindVars = std::make_shared(VPackBuilder::clone(querySlice.get("parameters"))); - - VPackSlice options = querySlice.get("options"); + auto bindVars = std::make_shared( + VPackBuilder::clone(querySlice.get("parameters"))); + auto options = std::make_shared( + VPackBuilder::clone(querySlice.get("options"))); auto query = new Query(_applicationV8, false, _vocbase, queryString.c_str(), diff --git a/arangod/Aql/Variable.cpp b/arangod/Aql/Variable.cpp index 7bfa9aef39..98d4eba476 100644 --- a/arangod/Aql/Variable.cpp +++ b/arangod/Aql/Variable.cpp @@ -22,12 +22,11 @@ //////////////////////////////////////////////////////////////////////////////// #include "Variable.h" -#include "Basics/JsonHelper.h" +#include "Basics/VelocyPackHelper.h" #include using namespace arangodb::aql; -using JsonHelper = arangodb::basics::JsonHelper; //////////////////////////////////////////////////////////////////////////////// /// @brief name of $OLD variable @@ -54,10 +53,11 @@ char const* const Variable::NAME_CURRENT = "$CURRENT"; Variable::Variable(std::string const& name, VariableId id) : name(name), value(nullptr), id(id) {} -Variable::Variable(arangodb::basics::Json const& json) - : Variable( - JsonHelper::checkAndGetStringValue(json.json(), "name"), - JsonHelper::checkAndGetNumericValue(json.json(), "id")) {} +Variable::Variable(arangodb::velocypack::Slice const slice) + : Variable(arangodb::basics::VelocyPackHelper::checkAndGetStringValue( + slice, "name"), + arangodb::basics::VelocyPackHelper::checkAndGetNumericValue< + VariableId>(slice, "id")) {} //////////////////////////////////////////////////////////////////////////////// /// @brief destroy the variable diff --git a/arangod/Aql/Variable.h b/arangod/Aql/Variable.h index 2b612570c4..ce204c5abb 100644 --- a/arangod/Aql/Variable.h +++ b/arangod/Aql/Variable.h @@ -25,10 +25,19 @@ #define ARANGOD_AQL_VARIABLE_H 1 #include "Basics/Common.h" -#include "Basics/JsonHelper.h" #include "Aql/types.h" + namespace arangodb { +namespace velocypack { +class Builder; +class Slice; +} + +namespace basics { +class Json; +} + namespace aql { struct Variable { @@ -38,7 +47,7 @@ struct Variable { Variable(std::string const&, VariableId); - explicit Variable(basics::Json const& json); + explicit Variable(arangodb::velocypack::Slice const); Variable* clone() const { return new Variable(name, id); } diff --git a/arangod/Aql/VariableGenerator.cpp b/arangod/Aql/VariableGenerator.cpp index 618757acf2..a9b14f64fc 100644 --- a/arangod/Aql/VariableGenerator.cpp +++ b/arangod/Aql/VariableGenerator.cpp @@ -24,6 +24,11 @@ #include "Aql/VariableGenerator.h" #include "Basics/Exceptions.h" +#include +#include +#include + + using namespace arangodb::aql; using Json = arangodb::basics::Json; @@ -130,12 +135,12 @@ Variable* VariableGenerator::createVariable(Variable const* original) { } //////////////////////////////////////////////////////////////////////////////// -/// @brief generate a variable from JSON +/// @brief generate a variable from VelocyPack //////////////////////////////////////////////////////////////////////////////// Variable* VariableGenerator::createVariable( - arangodb::basics::Json const& json) { - auto variable = new Variable(json); + VPackSlice const slice) { + auto variable = new Variable(slice); auto existing = getVariable(variable->id); if (existing != nullptr) { @@ -227,21 +232,22 @@ arangodb::basics::Json VariableGenerator::toJson( } //////////////////////////////////////////////////////////////////////////////// -/// @brief import from JSON +/// @brief import from VelocyPack //////////////////////////////////////////////////////////////////////////////// -void VariableGenerator::fromJson(Json const& query) { - Json jsonAllVariablesList = query.get("variables"); +void VariableGenerator::fromVelocyPack(VPackSlice const& query) { + VPackSlice allVariablesList = query.get("variables"); - if (!jsonAllVariablesList.isArray()) { + if (!allVariablesList.isArray()) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "variables needs to be an array"); } - auto len = jsonAllVariablesList.size(); + auto len = allVariablesList.length(); _variables.reserve(len); - for (size_t i = 0; i < len; i++) { - createVariable(jsonAllVariablesList.at(i)); + for (auto const& var : VPackArrayIterator(allVariablesList)) { + createVariable(var); } } + diff --git a/arangod/Aql/VariableGenerator.h b/arangod/Aql/VariableGenerator.h index 608ffa2bae..cbb3db1636 100644 --- a/arangod/Aql/VariableGenerator.h +++ b/arangod/Aql/VariableGenerator.h @@ -66,10 +66,10 @@ class VariableGenerator { Variable* createVariable(std::string const&, bool); ////////////////////////////////////////////////////////////////////////////// - /// @brief generate a variable from JSON + /// @brief generate a variable from VelocyPack ////////////////////////////////////////////////////////////////////////////// - Variable* createVariable(arangodb::basics::Json const&); + Variable* createVariable(arangodb::velocypack::Slice const); ////////////////////////////////////////////////////////////////////////////// /// @brief clones a variable from an existing one @@ -114,10 +114,10 @@ class VariableGenerator { arangodb::basics::Json toJson(TRI_memory_zone_t*) const; ////////////////////////////////////////////////////////////////////////////// - /// @brief import from JSON + /// @brief import from VelocyPack ////////////////////////////////////////////////////////////////////////////// - void fromJson(arangodb::basics::Json const& jsonAllVariablesList); + void fromVelocyPack(arangodb::velocypack::Slice const& allVariablesList); private: ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/RestHandler/RestCursorHandler.cpp b/arangod/RestHandler/RestCursorHandler.cpp index bc956ecb21..63357622e0 100644 --- a/arangod/RestHandler/RestCursorHandler.cpp +++ b/arangod/RestHandler/RestCursorHandler.cpp @@ -108,15 +108,14 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { bindVarsBuilder->add(bindVars); } - VPackBuilder optionsBuilder = buildOptions(slice); - VPackSlice options = optionsBuilder.slice(); + auto options = std::make_shared(buildOptions(slice)); VPackValueLength l; char const* queryString = querySlice.getString(l); arangodb::aql::Query query( _applicationV8, false, _vocbase, queryString, static_cast(l), bindVarsBuilder, - arangodb::basics::VelocyPackHelper::velocyPackToJson(options), + options, arangodb::aql::PART_MAIN); registerQuery(&query); @@ -139,10 +138,11 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { _response->setContentType("application/json; charset=utf-8"); std::shared_ptr extra = buildExtra(queryResult); + VPackSlice opts = options->slice(); size_t batchSize = arangodb::basics::VelocyPackHelper::getNumericValue( - options, "batchSize", 1000); + opts, "batchSize", 1000); size_t const n = TRI_LengthArrayJson(queryResult.json); if (n <= batchSize) { @@ -158,7 +158,7 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } result.add("hasMore", VPackValue(false)); - if (arangodb::basics::VelocyPackHelper::getBooleanValue(options, "count", + if (arangodb::basics::VelocyPackHelper::getBooleanValue(opts, "count", false)) { result.add("count", VPackValue(n)); } @@ -188,9 +188,9 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { TRI_ASSERT(cursors != nullptr); double ttl = arangodb::basics::VelocyPackHelper::getNumericValue( - options, "ttl", 30); + opts, "ttl", 30); bool count = arangodb::basics::VelocyPackHelper::getBooleanValue( - options, "count", false); + opts, "count", false); // steal the query JSON, cursor will take over the ownership auto j = queryResult.json; @@ -350,10 +350,7 @@ std::shared_ptr RestCursorHandler::buildExtra( } if (queryResult.profile != nullptr) { extra->add(VPackValue("profile")); - int res = arangodb::basics::JsonHelper::toVelocyPack(queryResult.profile, *extra); - if (res != TRI_ERROR_NO_ERROR) { - return nullptr; - } + extra->add(queryResult.profile->slice()); queryResult.profile = nullptr; } if (queryResult.warnings == nullptr) { diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index dbf2ed3d02..d252132d14 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1120,22 +1120,24 @@ static void JS_ExplainAql(v8::FunctionCallbackInfo const& args) { } } - std::unique_ptr options; + auto options = std::make_shared(); if (args.Length() > 2) { // handle options if (!args[2]->IsObject()) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } - - options.reset(TRI_ObjectToJson(isolate, args[2])); + int res = TRI_V8ToVPack(isolate, *options, args[2], false); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } } // bind parameters will be freed by the query later TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, queryString.c_str(), queryString.size(), - bindVars, options.release(), + bindVars, options, arangodb::aql::PART_MAIN); auto queryResult = query.explain(); @@ -1205,8 +1207,13 @@ static void JS_ExecuteAqlJson(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } - std::unique_ptr queryjson(TRI_ObjectToJson(isolate, args[0])); - std::unique_ptr options; + auto queryBuilder = std::make_shared(); + int res = TRI_V8ToVPack(isolate, *queryBuilder, args[0], false); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } + + auto options = std::make_shared(); if (args.Length() > 1) { // we have options! yikes! @@ -1214,15 +1221,15 @@ static void JS_ExecuteAqlJson(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } - options.reset(TRI_ObjectToJson(isolate, args[1])); + res = TRI_V8ToVPack(isolate, *options, args[1], false); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } } TRI_GET_GLOBALS(); - arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, - Json(TRI_UNKNOWN_MEM_ZONE, queryjson.release()), - options.get(), arangodb::aql::PART_MAIN); - - options.release(); + arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, queryBuilder, + options, arangodb::aql::PART_MAIN); auto queryResult = query.execute( static_cast(v8g->_queryRegistry)); @@ -1246,7 +1253,7 @@ static void JS_ExecuteAqlJson(v8::FunctionCallbackInfo const& args) { } if (queryResult.profile != nullptr) { result->ForceSet(TRI_V8_ASCII_STRING("profile"), - TRI_ObjectJson(isolate, queryResult.profile)); + TRI_VPackToV8(isolate, queryResult.profile->slice())); } if (queryResult.warnings == nullptr) { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); @@ -1291,7 +1298,7 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { std::shared_ptr bindVars; // options - std::unique_ptr options; + auto options = std::make_shared(); if (args.Length() > 1) { if (!args[1]->IsUndefined() && !args[1]->IsNull() && !args[1]->IsObject()) { @@ -1313,17 +1320,17 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR("expecting object for "); } - options.reset(TRI_ObjectToJson(isolate, args[2])); + int res = TRI_V8ToVPack(isolate, *options, args[2], false); + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_THROW_EXCEPTION(res); + } } // bind parameters will be freed by the query later TRI_GET_GLOBALS(); arangodb::aql::Query query(v8g->_applicationV8, true, vocbase, - queryString.c_str(), queryString.size(), - bindVars, options.get(), - arangodb::aql::PART_MAIN); - - options.release(); + queryString.c_str(), queryString.size(), bindVars, + options, arangodb::aql::PART_MAIN); auto queryResult = query.executeV8( isolate, static_cast(v8g->_queryRegistry)); @@ -1352,7 +1359,7 @@ static void JS_ExecuteAql(v8::FunctionCallbackInfo const& args) { } if (queryResult.profile != nullptr) { result->ForceSet(TRI_V8_ASCII_STRING("profile"), - TRI_ObjectJson(isolate, queryResult.profile)); + TRI_VPackToV8(isolate, queryResult.profile->slice())); } if (queryResult.warnings == nullptr) { result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate)); diff --git a/lib/Basics/VelocyPackHelper.h b/lib/Basics/VelocyPackHelper.h index b6e5e390a2..c3b4a256dd 100644 --- a/lib/Basics/VelocyPackHelper.h +++ b/lib/Basics/VelocyPackHelper.h @@ -126,6 +126,28 @@ class VelocyPackHelper { static std::string checkAndGetStringValue(VPackSlice const&, char const*); + ////////////////////////////////////////////////////////////////////////////// + /// @brief returns a Numeric sub-element, or throws if does not exist + /// or it is not a Number + ////////////////////////////////////////////////////////////////////////////// + + template + static T checkAndGetNumericValue(VPackSlice const& slice, char const* name) { + TRI_ASSERT(slice.isObject()); + if (!slice.hasKey(name)) { + std::string msg = + "The attribute '" + std::string(name) + "' was not found."; + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, msg); + } + VPackSlice const sub = slice.get(name); + if (!sub.isNumber()) { + std::string msg = + "The attribute '" + std::string(name) + "' is not a number."; + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, msg); + } + return sub.getNumericValue(); + } + ////////////////////////////////////////////////////////////////////////////// /// @brief returns a string value, or the default value if it is not a string //////////////////////////////////////////////////////////////////////////////