HttpHandler::status_t RestVersionHandler::execute() { try { VPackBuilder result; result.add(VPackValue(VPackValueType::Object)); result.add("server", VPackValue("arango")); result.add("version", VPackValue(ARANGODB_VERSION)); bool found; std::string const& detailsStr = _request->value("details", found); if (found && StringUtils::boolean(detailsStr)) { result.add("details", VPackValue(VPackValueType::Object)); Version::getVPack(result); if (application_features::ApplicationServer::server != nullptr) { auto server = application_features::ApplicationServer::server ->getFeature<ServerFeature>("Server"); result.add("mode", VPackValue(server->operationModeString())); } result.close(); } result.close(); generateResult(GeneralResponse::ResponseCode::OK, result.slice()); } catch (...) { // Ignore this error } return status_t(HANDLER_DONE); }
std::string AuthInfo::generateJwt(VPackBuilder const& payload) { if (!payload.slice().isObject()) { std::string error = "Need an object to generate a JWT. Got: "; error += payload.slice().typeName(); throw std::runtime_error(error); } bool hasIss = payload.slice().hasKey("iss"); bool hasIat = payload.slice().hasKey("iat"); VPackBuilder bodyBuilder; if (hasIss && hasIat) { bodyBuilder = payload; } else { VPackObjectBuilder p(&bodyBuilder); if (!hasIss) { bodyBuilder.add("iss", VPackValue("arangodb")); } if (!hasIat) { bodyBuilder.add("iat", VPackValue(TRI_microtime() / 1000)); } for (auto const& obj : VPackObjectIterator(payload.slice())) { bodyBuilder.add(obj.key.copyString(), obj.value); } } return generateRawJwt(bodyBuilder); }
VPackMessageNoOwnBuffer VppResponse::prepareForNetwork() { // initalize builder with vpackbuffer. then we do not need to // steal the header and can avoid the shared pointer VPackBuilder builder; builder.openArray(); builder.add(VPackValue(int(1))); builder.add(VPackValue(int(2))); // 2 == response builder.add( VPackValue(static_cast<int>(meta::underlyingValue(_responseCode)))); builder.close(); _header = builder.steal(); if (_vpackPayloads.empty()) { if (_generateBody) { LOG_TOPIC(INFO, Logger::REQUESTS) << "Response should generate body but no Data available"; _generateBody = false; // no body availalbe } return VPackMessageNoOwnBuffer(VPackSlice(_header->data()), VPackSlice::noneSlice(), _messageId, _generateBody); } else { std::vector<VPackSlice> slices; for (auto const& buffer : _vpackPayloads) { slices.emplace_back(buffer.data()); } return VPackMessageNoOwnBuffer(VPackSlice(_header->data()), std::move(slices), _messageId, _generateBody); } }
void arangodb::traverser::TraverserOptions::toVelocyPackIndexes(VPackBuilder& builder) const { VPackObjectBuilder guard(&builder); // base indexes builder.add("base", VPackValue(VPackValueType::Array)); for (auto const& it : _baseLookupInfos) { for (auto const& it2 : it.idxHandles) { builder.openObject(); it2.getIndex()->toVelocyPack(builder, false); builder.close(); } } builder.close(); // depth lookup indexes builder.add("levels", VPackValue(VPackValueType::Object)); for (auto const& it : _depthLookupInfo) { builder.add(VPackValue(std::to_string(it.first))); builder.add(VPackValue(VPackValueType::Array)); for (auto const& it2 : it.second) { for (auto const& it3 : it2.idxHandles) { builder.openObject(); it3.getIndex()->toVelocyPack(builder, false); builder.close(); } } builder.close(); } builder.close(); }
void RestWalHandler::transactions() { auto const& info = arangodb::wal::LogfileManager::instance()->runningTransactions(); VPackBuilder builder; builder.openObject(); builder.add("runningTransactions", VPackValue(static_cast<double>(std::get<0>(info)))); // lastCollectedId { auto value = std::get<1>(info); if (value == UINT64_MAX) { builder.add("minLastCollected", VPackValue(VPackValueType::Null)); } else { builder.add("minLastCollected", VPackValue(value)); } } // lastSealedId { auto value = std::get<2>(info); if (value == UINT64_MAX) { builder.add("minLastSealed", VPackValue(VPackValueType::Null)); } else { builder.add("minLastSealed", VPackValue(value)); } } builder.close(); generateResult(rest::ResponseCode::OK, builder.slice()); }
void arangodb::traverser::ShortestPath::edgeToVelocyPack(Transaction*, ManagedDocumentResult* mmdr, size_t position, VPackBuilder& builder) { TRI_ASSERT(position < length()); if (position == 0) { builder.add(basics::VelocyPackHelper::NullValue()); } else { TRI_ASSERT(position - 1 < _edges.size()); builder.add(_edges[position - 1]); } }
HttpHandler::status_t RestAuthHandler::execute() { auto const type = _request->requestType(); if (type != GeneralRequest::RequestType::POST) { generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED); return status_t(HANDLER_DONE); } VPackOptions options = VPackOptions::Defaults; options.checkAttributeUniqueness = true; bool parseSuccess; std::shared_ptr<VPackBuilder> parsedBody = parseVelocyPackBody(&options, parseSuccess); if (!parseSuccess) { return badRequest(); } VPackSlice slice = parsedBody->slice(); if (!slice.isObject()) { return badRequest(); } VPackSlice usernameSlice = slice.get("username"); VPackSlice passwordSlice = slice.get("password"); if (!usernameSlice.isString() || !passwordSlice.isString()) { return badRequest(); } std::string const username = usernameSlice.copyString(); std::string const password = passwordSlice.copyString(); AuthResult auth = RestServerFeature::AUTH_INFO.checkPassword(username, password); if (auth._authorized) { VPackBuilder resultBuilder; { VPackObjectBuilder b(&resultBuilder); std::string jwt = generateJwt(username, password); resultBuilder.add("jwt", VPackValue(jwt)); resultBuilder.add("must_change_password", VPackValue(auth._mustChange)); } generateDocument(resultBuilder.slice(), true, &VPackOptions::Defaults); return status_t(HANDLER_DONE); } else { // mop: rfc 2616 10.4.2 (if credentials wrong 401) generateError(GeneralResponse::ResponseCode::UNAUTHORIZED, TRI_ERROR_HTTP_UNAUTHORIZED, "Wrong credentials"); return status_t(HANDLER_DONE); } }
void RestVocbaseBaseHandler::generatePreconditionFailed( std::string const& collectionName, std::string const& key, TRI_voc_rid_t rev) { VPackBuilder builder; builder.openObject(); builder.add(StaticStrings::IdString, VPackValue(assembleDocumentId(collectionName, key, false))); builder.add(StaticStrings::KeyString, VPackValue(key)); builder.add(StaticStrings::RevString, VPackValue(std::to_string(rev))); builder.close(); generatePreconditionFailed(builder.slice()); }
void TraverserExpression::toVelocyPack(VPackBuilder& builder) const { builder.openObject(); builder.add("isEdgeAccess", VPackValue(isEdgeAccess)); builder.add("comparisonType", VPackValue(static_cast<int32_t>(comparisonType))); builder.add(VPackValue("varAccess")); varAccess->toVelocyPack(builder, true); if (compareTo != nullptr) { builder.add("compareTo", compareTo->slice()); } builder.close(); }
void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder) const { VPackObjectBuilder guard(&builder); builder.add("minDepth", VPackValue(minDepth)); builder.add("maxDepth", VPackValue(maxDepth)); builder.add("bfs", VPackValue(useBreadthFirst)); switch (uniqueVertices) { case arangodb::traverser::TraverserOptions::UniquenessLevel::NONE: builder.add("uniqueVertices", VPackValue("none")); break; case arangodb::traverser::TraverserOptions::UniquenessLevel::PATH: builder.add("uniqueVertices", VPackValue("path")); break; case arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL: builder.add("uniqueVertices", VPackValue("global")); break; } switch (uniqueEdges) { case arangodb::traverser::TraverserOptions::UniquenessLevel::NONE: builder.add("uniqueEdges", VPackValue("none")); break; case arangodb::traverser::TraverserOptions::UniquenessLevel::PATH: builder.add("uniqueEdges", VPackValue("path")); break; case arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL: builder.add("uniqueEdges", VPackValue("global")); break; } }
/// @brief toVelocyPack void ReplaceNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const { ModificationNode::toVelocyPackHelper(nodes, verbose); nodes.add(VPackValue("inDocVariable")); _inDocVariable->toVelocyPack(nodes); // inKeyVariable might be empty if (_inKeyVariable != nullptr) { nodes.add(VPackValue("inKeyVariable")); _inKeyVariable->toVelocyPack(nodes); } // And close it: nodes.close(); }
/// @brief toVelocyPack void UpsertNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const { ModificationNode::toVelocyPackHelper(nodes, verbose); nodes.add(VPackValue("inDocVariable")); _inDocVariable->toVelocyPack(nodes); nodes.add(VPackValue("insertVariable")); _insertVariable->toVelocyPack(nodes); nodes.add(VPackValue("updateVariable")); _updateVariable->toVelocyPack(nodes); nodes.add("isReplace", VPackValue(_isReplace)); // And close it: nodes.close(); }
TraverserExpression::TraverserExpression(VPackSlice const& slice) { isEdgeAccess = slice.get("isEdgeAccess").getBool(); comparisonType = static_cast<aql::AstNodeType>( slice.get("comparisonType").getNumber<uint32_t>()); auto registerNode = [&](aql::AstNode const* node) -> void { _nodeRegister.emplace_back(node); }; auto registerString = [&](std::string const& str) -> char const* { auto copy = std::make_unique<std::string>(str.c_str(), str.size()); _stringRegister.emplace_back(copy.get()); auto p = copy.release(); TRI_ASSERT(p != nullptr); TRI_ASSERT(p->c_str() != nullptr); return p->c_str(); // should never change its position, even if vector // grows/shrinks }; VPackSlice compareToSlice = slice.get("compareTo"); VPackBuilder* builder = new VPackBuilder; try { builder->add(compareToSlice); } catch (...) { delete builder; throw; } compareTo.reset(builder); // If this fails everything before does not leak varAccess = new aql::AstNode(registerNode, registerString, slice.get("varAccess")); }
uint64_t VelocyPackHelper::hashByAttributes( VPackSlice slice, std::vector<std::string> const& attributes, bool docComplete, int& error, std::string const& key) { uint64_t hash = TRI_FnvHashBlockInitial(); error = TRI_ERROR_NO_ERROR; slice = slice.resolveExternal(); if (slice.isObject()) { for (auto const& attr : attributes) { VPackSlice sub = slice.get(attr).resolveExternal(); if (sub.isNone()) { if (attr == StaticStrings::KeyString && !key.empty()) { VPackBuilder temporaryBuilder; temporaryBuilder.add(VPackValue(key)); hash = temporaryBuilder.slice().normalizedHash(hash); continue; } if (!docComplete) { error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; } // Null is equal to None/not present sub = VPackSlice::nullSlice(); } hash = sub.normalizedHash(hash); } } return hash; }
/// @brief create an AqlValue from a vector of AqlItemBlock*s AqlValue AqlValue::CreateFromBlocks( arangodb::AqlTransaction* trx, std::vector<AqlItemBlock*> const& src, std::vector<std::string> const& variableNames) { VPackBuilder builder; builder.openArray(); for (auto const& current : src) { RegisterId const n = current->getNrRegs(); std::vector<RegisterId> registers; for (RegisterId j = 0; j < n; ++j) { // temporaries don't have a name and won't be included if (!variableNames[j].empty()) { registers.emplace_back(j); } } for (size_t i = 0; i < current->size(); ++i) { builder.openObject(); // only enumerate the registers that are left for (auto const& reg : registers) { builder.add(VPackValue(variableNames[reg])); current->getValueReference(i, reg).toVelocyPack(trx, builder, false); } builder.close(); } } builder.close(); return AqlValue(builder); }
int Syncer::createCollection(VPackSlice const& slice, arangodb::LogicalCollection** dst) { if (dst != nullptr) { *dst = nullptr; } if (!slice.isObject()) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } std::string const name = VelocyPackHelper::getStringValue(slice, "name", ""); if (name.empty()) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_voc_cid_t const cid = getCid(slice); if (cid == 0) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_col_type_e const type = static_cast<TRI_col_type_e>(VelocyPackHelper::getNumericValue<int>( slice, "type", TRI_COL_TYPE_DOCUMENT)); arangodb::LogicalCollection* col = getCollectionByIdOrName(cid, name); if (col != nullptr && col->type() == type) { // collection already exists. TODO: compare attributes return TRI_ERROR_NO_ERROR; } // merge in "isSystem" attribute VPackBuilder s; s.openObject(); s.add("isSystem", VPackValue(true)); s.close(); VPackBuilder merged = VPackCollection::merge(s.slice(), slice, true); int res = TRI_ERROR_NO_ERROR; try { col = _vocbase->createCollection(merged.slice(), cid, true); } catch (basics::Exception const& ex) { res = ex.code(); } catch (...) { res = TRI_ERROR_INTERNAL; } if (res != TRI_ERROR_NO_ERROR) { return res; } TRI_ASSERT(col != nullptr); if (dst != nullptr) { *dst = col; } return TRI_ERROR_NO_ERROR; }
void RemoveNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const { ModificationNode::toVelocyPackHelper(nodes, verbose); nodes.add(VPackValue("inVariable")); _inVariable->toVelocyPack(nodes); // And close it: nodes.close(); }
void RestVocbaseBaseHandler::generatePreconditionFailed( VPackSlice const& slice) { createResponse(GeneralResponse::ResponseCode::PRECONDITION_FAILED); if (slice.isObject()) { // single document case std::string const rev = VelocyPackHelper::getStringValue(slice, StaticStrings::RevString, ""); _response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\""); } VPackBuilder builder; { VPackObjectBuilder guard(&builder); builder.add("error", VPackValue(true)); builder.add("code", VPackValue(static_cast<int32_t>( GeneralResponse::ResponseCode::PRECONDITION_FAILED))); builder.add("errorNum", VPackValue(TRI_ERROR_ARANGO_CONFLICT)); builder.add("errorMessage", VPackValue("precondition failed")); if (slice.isObject()) { builder.add(StaticStrings::IdString, slice.get(StaticStrings::IdString)); builder.add(StaticStrings::KeyString, slice.get(StaticStrings::KeyString)); builder.add(StaticStrings::RevString, slice.get(StaticStrings::RevString)); } else { builder.add("result", slice); } } auto transactionContext(StandaloneTransactionContext::Create(_vocbase)); writeResult(builder.slice(), *(transactionContext->getVPackOptionsForDump())); }
void AuthInfo::insertInitial() { if (!_authInfo.empty()) { return; } try { VPackBuilder builder; builder.openArray(); // The only users object builder.add(VPackValue(VPackValueType::Object)); // username builder.add("user", VPackValue("root")); builder.add("authData", VPackValue(VPackValueType::Object)); // simple auth builder.add("simple", VPackValue(VPackValueType::Object)); builder.add("method", VPackValue("sha256")); char const* salt = "c776f5f4"; builder.add("salt", VPackValue(salt)); char const* hash = "ef74bc6fd59ac713bf5929c5ac2f42233e50d4d58748178132ea46dec433bd5b"; builder.add("hash", VPackValue(hash)); builder.close(); // simple builder.add("active", VPackValue(true)); builder.close(); // authData builder.add("databases", VPackValue(VPackValueType::Object)); builder.add("*", VPackValue("rw")); builder.close(); builder.close(); // The user object builder.close(); // The Array populate(builder.slice()); } catch (...) { // No action } }
std::string AuthInfo::generateRawJwt(VPackBuilder const& bodyBuilder) { VPackBuilder headerBuilder; { VPackObjectBuilder h(&headerBuilder); headerBuilder.add("alg", VPackValue("HS256")); headerBuilder.add("typ", VPackValue("JWT")); } std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) + "." + StringUtils::encodeBase64(bodyBuilder.toJson())); std::string signature = sslHMAC(_jwtSecret.c_str(), _jwtSecret.length(), fullMessage.c_str(), fullMessage.length(), SslInterface::Algorithm::ALGORITHM_SHA256); return fullMessage + "." + StringUtils::encodeBase64U(signature); }
int RestoreFeature::tryCreateDatabase(ClientFeature* client, std::string const& name) { VPackBuilder builder; builder.openObject(); builder.add("name", VPackValue(name)); builder.add("users", VPackValue(VPackValueType::Array)); builder.openObject(); builder.add("username", VPackValue(client->username())); builder.add("passwd", VPackValue(client->password())); builder.close(); builder.close(); builder.close(); std::string const body = builder.slice().toJson(); std::unique_ptr<SimpleHttpResult> response( _httpClient->request(GeneralRequest::RequestType::POST, "/_api/database", body.c_str(), body.size())); if (response == nullptr || !response->isComplete()) { return TRI_ERROR_INTERNAL; } auto returnCode = response->getHttpReturnCode(); if (returnCode == static_cast<int>(GeneralResponse::ResponseCode::OK) || returnCode == static_cast<int>(GeneralResponse::ResponseCode::CREATED)) { // all ok return TRI_ERROR_NO_ERROR; } if (returnCode == static_cast<int>(GeneralResponse::ResponseCode::UNAUTHORIZED) || returnCode == static_cast<int>(GeneralResponse::ResponseCode::FORBIDDEN)) { // invalid authorization _httpClient->setErrorMessage(getHttpErrorMessage(response.get(), nullptr), false); return TRI_ERROR_FORBIDDEN; } // any other error _httpClient->setErrorMessage(getHttpErrorMessage(response.get(), nullptr), false); return TRI_ERROR_INTERNAL; }
void SingleServerTraversalPath::lastEdgeToVelocyPack(arangodb::Transaction* trx, VPackBuilder& result) { if (_path.edges.empty()) { result.add(arangodb::basics::VelocyPackHelper::NullValue()); return; } auto cached = _traverser->_edges.find(_path.edges.back()); // All edges are cached!! TRI_ASSERT(cached != _traverser->_edges.end()); result.addExternal((*cached).second); }
/// @brief toVelocyPack, for SortNode void SortNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const { ExecutionNode::toVelocyPackHelperGeneric(nodes, verbose); // call base class method nodes.add(VPackValue("elements")); { VPackArrayBuilder guard(&nodes); for (auto const& it : _elements) { VPackObjectBuilder obj(&nodes); nodes.add(VPackValue("inVariable")); it.first->toVelocyPack(nodes); nodes.add("ascending", VPackValue(it.second)); } } nodes.add("stable", VPackValue(_stable)); // And close it: nodes.close(); }
bool RestEdgesHandler::getEdgesForVertexList( VPackSlice const ids, std::vector<traverser::TraverserExpression*> const& expressions, TRI_edge_direction_e direction, SingleCollectionTransaction& trx, VPackBuilder& result, size_t& scannedIndex, size_t& filtered) { TRI_ASSERT(ids.isArray()); trx.orderDitch(trx.cid()); // will throw when it fails std::string const collectionName = trx.resolver()->getCollectionName(trx.cid()); Transaction::IndexHandle indexId = trx.edgeIndexHandle(collectionName); VPackBuilder searchValueBuilder; EdgeIndex::buildSearchValueFromArray(direction, ids, searchValueBuilder); VPackSlice search = searchValueBuilder.slice(); std::unique_ptr<OperationCursor> cursor = trx.indexScan(collectionName, arangodb::Transaction::CursorType::INDEX, indexId, search, nullptr, 0, UINT64_MAX, 1000, false); if (cursor->failed()) { THROW_ARANGO_EXCEPTION(cursor->code); } auto opRes = std::make_shared<OperationResult>(TRI_ERROR_NO_ERROR); while (cursor->hasMore()) { cursor->getMore(opRes); if (opRes->failed()) { THROW_ARANGO_EXCEPTION(opRes->code); } VPackSlice edges = opRes->slice(); TRI_ASSERT(edges.isArray()); // generate result scannedIndex += static_cast<size_t>(edges.length()); for (auto const& edge : VPackArrayIterator(edges)) { bool add = true; if (!expressions.empty()) { for (auto& exp : expressions) { if (exp->isEdgeAccess && !exp->matchesCheck(&trx, edge)) { ++filtered; add = false; break; } } } if (add) { result.add(edge); } } } return true; }
void VelocyPackHelper::SanitizeExternals(VPackSlice const input, VPackBuilder& output) { if (input.isExternal()) { output.add(input.resolveExternal()); } else if (input.isObject()) { output.openObject(); for (auto const& it : VPackObjectIterator(input)) { output.add(VPackValue(it.key.copyString())); SanitizeExternals(it.value, output); } output.close(); } else if (input.isArray()) { output.openArray(); for (auto const& it : VPackArrayIterator(input)) { SanitizeExternals(it, output); } output.close(); } else { output.add(input); } }
void SingleServerTraversalPath::pathToVelocyPack(arangodb::Transaction* trx, VPackBuilder& result) { result.openObject(); result.add(VPackValue("edges")); result.openArray(); for (auto const& it : _path.edges) { auto cached = _traverser->_edges.find(it); // All edges are cached!! TRI_ASSERT(cached != _traverser->_edges.end()); result.addExternal((*cached).second); } result.close(); result.add(VPackValue("vertices")); result.openArray(); for (auto const& it : _path.vertices) { result.add(_traverser->fetchVertexData(it).slice()); } result.close(); result.close(); }
/// @brief toVelocyPack void ModificationNode::toVelocyPackHelper(VPackBuilder& builder, bool verbose) const { ExecutionNode::toVelocyPackHelperGeneric(builder, verbose); // call base class method // Now put info about vocbase and cid in there builder.add("database", VPackValue(_vocbase->name())); builder.add("collection", VPackValue(_collection->getName())); // add out variables if (_outVariableOld != nullptr) { builder.add(VPackValue("outVariableOld")); _outVariableOld->toVelocyPack(builder); } if (_outVariableNew != nullptr) { builder.add(VPackValue("outVariableNew")); _outVariableNew->toVelocyPack(builder); } builder.add(VPackValue("modificationFlags")); _options.toVelocyPack(builder); }
/// @brief toVelocyPack void InsertNode::toVelocyPackHelper(VPackBuilder& nodes, bool verbose) const { ModificationNode::toVelocyPackHelper(nodes, verbose); // call base class method // Now put info about vocbase and cid in there nodes.add(VPackValue("inVariable")); _inVariable->toVelocyPack(nodes); // And close it: nodes.close(); }
/// @brief getSome AqlItemBlock* RemoteBlock::getSome(size_t atLeast, size_t atMost) { DEBUG_BEGIN_BLOCK(); // For every call we simply forward via HTTP traceGetSomeBegin(); VPackBuilder builder; builder.openObject(); builder.add("atLeast", VPackValue(atLeast)); builder.add("atMost", VPackValue(atMost)); builder.close(); std::string bodyString(builder.slice().toJson()); std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/getSome/", bodyString); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: std::shared_ptr<VPackBuilder> responseBodyBuilder = res->result->getBodyVelocyPack(); VPackSlice responseBody = responseBodyBuilder->slice(); ExecutionStats newStats(responseBody.get("stats")); _engine->_stats.addDelta(_deltaStats, newStats); _deltaStats = newStats; if (VelocyPackHelper::getBooleanValue(responseBody, "exhausted", true)) { traceGetSomeEnd(nullptr); return nullptr; } auto r = new arangodb::aql::AqlItemBlock(responseBody); traceGetSomeEnd(r); return r; // cppcheck-suppress style DEBUG_END_BLOCK(); }
int Syncer::createCollection(VPackSlice const& slice, TRI_vocbase_col_t** dst) { if (dst != nullptr) { *dst = nullptr; } if (!slice.isObject()) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } std::string const name = VelocyPackHelper::getStringValue(slice, "name", ""); if (name.empty()) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_voc_cid_t const cid = getCid(slice); if (cid == 0) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_col_type_e const type = static_cast<TRI_col_type_e>(VelocyPackHelper::getNumericValue<int>( slice, "type", static_cast<int>(TRI_COL_TYPE_DOCUMENT))); TRI_vocbase_col_t* col = getCollectionByIdOrName(cid, name); if (col != nullptr && static_cast<TRI_col_type_t>(col->_type) == static_cast<TRI_col_type_t>(type)) { // collection already exists. TODO: compare attributes return TRI_ERROR_NO_ERROR; } // merge in "isSystem" attribute VPackBuilder s; s.openObject(); s.add("isSystem", VPackValue(true)); s.close(); VPackBuilder merged = VPackCollection::merge(s.slice(), slice, true); VocbaseCollectionInfo params(_vocbase, name.c_str(), merged.slice()); col = TRI_CreateCollectionVocBase(_vocbase, params, cid, true); if (col == nullptr) { return TRI_errno(); } if (dst != nullptr) { *dst = col; } return TRI_ERROR_NO_ERROR; }