1
0
Fork 0

Merge branch 'spdvpk' of ssh://github.com/ArangoDB/ArangoDB into spdvpk

This commit is contained in:
Max Neunhoeffer 2016-03-09 13:28:43 +01:00
commit 5b807d6753
14 changed files with 460 additions and 497 deletions

View File

@ -33,6 +33,7 @@
#include "VocBase/collection.h"
#include <velocypack/Iterator.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb::aql;
@ -1046,25 +1047,22 @@ AstNode* Ast::createNodeIntersectedArray(AstNode const* lhs,
size_t const nl = lhs->numMembers();
size_t const nr = rhs->numMembers();
std::unordered_map<TRI_json_t*, AstNode const*, arangodb::basics::JsonHash,
arangodb::basics::JsonEqual>
cache(nl + nr, arangodb::basics::JsonHash(),
arangodb::basics::JsonEqual());
std::unordered_map<VPackSlice, AstNode const*> cache(nl + nr);
for (size_t i = 0; i < nl; ++i) {
auto member = lhs->getMemberUnchecked(i);
auto json = member->computeJson();
VPackSlice slice = member->computeValue();
cache.emplace(json, member);
cache.emplace(slice, member);
}
auto node = createNodeArray();
for (size_t i = 0; i < nr; ++i) {
auto member = rhs->getMemberUnchecked(i);
auto json = member->computeJson();
VPackSlice slice = member->computeValue();
auto it = cache.find(json);
auto it = cache.find(slice);
if (it != cache.end()) {
node->addMember((*it).second);
@ -1085,10 +1083,7 @@ AstNode* Ast::createNodeUnionizedArray(AstNode const* lhs, AstNode const* rhs) {
size_t const nl = lhs->numMembers();
size_t const nr = rhs->numMembers();
std::unordered_map<TRI_json_t*, AstNode const*, arangodb::basics::JsonHash,
arangodb::basics::JsonEqual>
cache(nl + nr, arangodb::basics::JsonHash(),
arangodb::basics::JsonEqual());
std::unordered_map<VPackSlice, AstNode const*> cache(nl + nr);
for (size_t i = 0; i < nl + nr; ++i) {
AstNode* member;
@ -1097,9 +1092,9 @@ AstNode* Ast::createNodeUnionizedArray(AstNode const* lhs, AstNode const* rhs) {
} else {
member = rhs->getMemberUnchecked(i - nl);
}
auto json = member->computeJson();
VPackSlice slice = member->computeValue();
cache.emplace(json, member);
cache.emplace(slice, member);
}
auto node = createNodeArray();
@ -2039,16 +2034,14 @@ AstNode const* Ast::deduplicateArray(AstNode const* node) {
// TODO: sort values in place first and compare two adjacent members each
std::unordered_map<TRI_json_t*, AstNode const*, arangodb::basics::JsonHash,
arangodb::basics::JsonEqual>
cache(n, arangodb::basics::JsonHash(), arangodb::basics::JsonEqual());
std::unordered_map<VPackSlice, AstNode const*> cache(n);
for (size_t i = 0; i < n; ++i) {
auto member = node->getMemberUnchecked(i);
auto json = member->computeJson();
VPackSlice slice = member->computeValue();
if (cache.find(json) == cache.end()) {
cache.emplace(json, member);
if (cache.find(slice) == cache.end()) {
cache.emplace(slice, member);
}
}

View File

@ -40,6 +40,7 @@
#endif
#include <velocypack/Builder.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
#include <array>
@ -432,7 +433,7 @@ static bool IsEmptyString(char const* p, size_t length) {
////////////////////////////////////////////////////////////////////////////////
AstNode::AstNode(AstNodeType type)
: type(type), flags(0), computedJson(nullptr) {}
: type(type), flags(0), computedValue(nullptr) {}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a node, with defining a value type
@ -441,7 +442,7 @@ AstNode::AstNode(AstNodeType type)
AstNode::AstNode(AstNodeType type, AstNodeValueType valueType) : AstNode(type) {
value.type = valueType;
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@ -453,7 +454,7 @@ AstNode::AstNode(bool v, AstNodeValueType valueType)
TRI_ASSERT(valueType == VALUE_TYPE_BOOL);
value.value._bool = v;
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@ -465,7 +466,7 @@ AstNode::AstNode(int64_t v, AstNodeValueType valueType)
TRI_ASSERT(valueType == VALUE_TYPE_INT);
value.value._int = v;
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@ -477,7 +478,7 @@ AstNode::AstNode(char const* v, size_t length, AstNodeValueType valueType)
TRI_ASSERT(valueType == VALUE_TYPE_STRING);
setStringValue(v, length);
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@ -487,7 +488,7 @@ AstNode::AstNode(char const* v, size_t length, AstNodeValueType valueType)
AstNode::AstNode(Ast* ast, arangodb::basics::Json const& json)
: AstNode(getNodeTypeFromJson(json)) {
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
auto query = ast->query();
@ -676,7 +677,7 @@ AstNode::AstNode(std::function<void(AstNode*)> registerNode,
arangodb::basics::Json const& json)
: AstNode(getNodeTypeFromJson(json)) {
TRI_ASSERT(flags == 0);
TRI_ASSERT(computedJson == nullptr);
TRI_ASSERT(computedValue == nullptr);
switch (type) {
case NODE_TYPE_ATTRIBUTE_ACCESS: {
@ -830,9 +831,8 @@ AstNode::AstNode(std::function<void(AstNode*)> registerNode,
////////////////////////////////////////////////////////////////////////////////
AstNode::~AstNode() {
if (computedJson != nullptr) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, computedJson);
computedJson = nullptr;
if (computedValue != nullptr) {
delete[] computedValue;
}
}
@ -936,21 +936,23 @@ void AstNode::dump(int level) const {
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief compute the JSON for a constant value node
/// the JSON is owned by the node and must not be freed by the caller
/// @brief compute the value for a constant value node
/// the value is owned by the node and must not be freed by the caller
/// note that the return value might be NULL in case of OOM
////////////////////////////////////////////////////////////////////////////////
TRI_json_t* AstNode::computeJson() const {
VPackSlice AstNode::computeValue() const {
TRI_ASSERT(isConstant());
if (computedJson == nullptr) {
// note: the following may fail but we do not need to
// check that here
computedJson = toJsonValue(TRI_UNKNOWN_MEM_ZONE);
if (computedValue == nullptr) {
VPackBuilder builder;
toVelocyPackValue(builder);
computedValue = new uint8_t[builder.size()];
memcpy(computedValue, builder.data(), builder.size());
}
return computedJson;
return VPackSlice(computedValue);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -30,6 +30,8 @@
#include "Basics/json.h"
#include "Basics/JsonHelper.h"
#include <velocypack/Slice.h>
#include <functional>
#include <iosfwd>
@ -291,12 +293,12 @@ struct AstNode {
#endif
//////////////////////////////////////////////////////////////////////////////
/// @brief compute the JSON for a constant value node
/// the JSON is owned by the node and must not be freed by the caller
/// @brief compute the value for a constant value node
/// the value is owned by the node and must not be freed by the caller
/// note that the return value might be NULL in case of OOM
//////////////////////////////////////////////////////////////////////////////
TRI_json_t* computeJson() const;
arangodb::velocypack::Slice computeValue() const;
//////////////////////////////////////////////////////////////////////////////
/// @brief sort the members of an (array) node
@ -932,10 +934,10 @@ struct AstNode {
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief precomputed JSON value (used when executing expressions)
/// @brief precomputed VPack value (used when executing expressions)
//////////////////////////////////////////////////////////////////////////////
TRI_json_t mutable* computedJson;
uint8_t mutable* computedValue;
//////////////////////////////////////////////////////////////////////////////
/// @brief the node's sub nodes

View File

@ -104,7 +104,7 @@ Expression::~Expression() {
switch (_type) {
case JSON:
TRI_ASSERT(_data != nullptr);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _data);
delete[] _data;
break;
case ATTRIBUTE: {
@ -154,9 +154,7 @@ AqlValue$ Expression::execute(arangodb::AqlTransaction* trx,
case JSON: {
// TODO
TRI_ASSERT(_data != nullptr);
VPackBuilder builder;
JsonHelper::toVelocyPack(_data, builder);
return AqlValue$(builder);
return AqlValue$(VPackSlice(_data), AqlValue$::AqlValueType::REFERENCE_STICKY);
}
case SIMPLE: {
@ -171,22 +169,8 @@ AqlValue$ Expression::execute(arangodb::AqlTransaction* trx,
case V8: {
TRI_ASSERT(_func != nullptr);
try {
ISOLATE;
return _func->execute(isolate, _ast->query(), trx, argv, startPos, vars,
regs);
} catch (arangodb::basics::Exception& ex) {
if (_ast->query()->verboseErrors()) {
ex.addToMessage(" while evaluating expression ");
auto json = _node->toJson(TRI_UNKNOWN_MEM_ZONE, false);
if (json != nullptr) {
ex.addToMessage(arangodb::basics::JsonHelper::toString(json));
TRI_Free(TRI_UNKNOWN_MEM_ZONE, json);
}
}
throw;
}
ISOLATE;
return _func->execute(isolate, _ast->query(), trx, argv, startPos, vars, regs);
}
case UNPROCESSED: {
@ -408,12 +392,11 @@ void Expression::buildExpression() {
if (_type == JSON) {
TRI_ASSERT(_data == nullptr);
// generate a constant value
_data = _node->toJsonValue(TRI_UNKNOWN_MEM_ZONE);
VPackBuilder builder;
_node->toVelocyPackValue(builder);
if (_data == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"invalid json in simple expression");
}
_data = new uint8_t[builder.size()];
memcpy(_data, builder.data(), builder.size());
} else if (_type == V8) {
// generate a V8 expression
_func = _executor->generateExpression(_node);
@ -651,16 +634,7 @@ AqlValue$ Expression::executeSimpleExpressionArray(
std::vector<Variable const*> const& vars,
std::vector<RegisterId> const& regs) {
if (node->isConstant()) {
auto json = node->computeJson();
if (json == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
VPackBuilder builder;
JsonHelper::toVelocyPack(json, builder);
return AqlValue$(builder);
return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
}
size_t const n = node->numMembers();
@ -689,16 +663,7 @@ AqlValue$ Expression::executeSimpleExpressionObject(
std::vector<Variable const*> const& vars,
std::vector<RegisterId> const& regs) {
if (node->isConstant()) {
auto json = node->computeJson();
if (json == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
VPackBuilder builder;
JsonHelper::toVelocyPack(json, builder);
return AqlValue$(builder);
return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
}
VPackBuilder builder;
@ -725,15 +690,7 @@ AqlValue$ Expression::executeSimpleExpressionObject(
////////////////////////////////////////////////////////////////////////////////
AqlValue$ Expression::executeSimpleExpressionValue(AstNode const* node) {
auto json = node->computeJson();
if (json == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
VPackBuilder builder;
JsonHelper::toVelocyPack(json, builder);
return AqlValue$(builder);
return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
}
////////////////////////////////////////////////////////////////////////////////
@ -1270,14 +1227,14 @@ AqlValue$ Expression::executeSimpleExpressionArithmetic(
trx, argv, startPos, vars, regs, true);
if (lhs.isObject()) {
return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
return AqlValue$(VelocyPackHelper::NullValue());
}
AqlValue$ rhs = executeSimpleExpression(node->getMember(1),
trx, argv, startPos, vars, regs, true);
if (rhs.isObject()) {
return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
return AqlValue$(VelocyPackHelper::NullValue());
}
double const l = lhs.toDouble();
@ -1298,17 +1255,17 @@ AqlValue$ Expression::executeSimpleExpressionArithmetic(
case NODE_TYPE_OPERATOR_BINARY_DIV:
if (r == 0.0) {
RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
return AqlValue$(VelocyPackHelper::NullValue());
}
return AqlValue$(builder);
case NODE_TYPE_OPERATOR_BINARY_MOD:
if (r == 0.0) {
RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO);
return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
return AqlValue$(VelocyPackHelper::NullValue());
}
builder.add(VPackValue(fmod(l, r)));
return AqlValue$(builder);
default:
return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY);
return AqlValue$(VelocyPackHelper::NullValue());
}
}

View File

@ -490,7 +490,7 @@ class Expression {
union {
V8Expression* _func;
struct TRI_json_t* _data;
uint8_t* _data;
AttributeAccessor* _accessor;
};

View File

@ -36,9 +36,11 @@
#include "FulltextIndex/fulltext-result.h"
#include "FulltextIndex/fulltext-query.h"
#include "Indexes/Index.h"
#include "Indexes/EdgeIndex.h"
#include "Indexes/FulltextIndex.h"
#include "Indexes/GeoIndex2.h"
#include "Rest/SslInterface.h"
#include "Utils/OperationCursor.h"
#include "Utils/OperationOptions.h"
#include "Utils/OperationResult.h"
#include "Utils/Transaction.h"
@ -64,6 +66,15 @@ using VertexId = arangodb::traverser::VertexId;
thread_local std::unordered_map<std::string, RegexMatcher*>* RegexCache =
nullptr;
////////////////////////////////////////////////////////////////////////////////
/// @brief Insert a mptr into the result
////////////////////////////////////////////////////////////////////////////////
static void InsertMasterPointer(TRI_doc_mptr_t const* mptr, VPackBuilder& builder) {
builder.add(VPackValue(static_cast<void const*>(mptr->vpack()),
VPackValueType::External));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clear the regex cache in a thread
////////////////////////////////////////////////////////////////////////////////
@ -434,121 +445,10 @@ static bool SortNumberList(VPackSlice const& values,
return true;
}
static inline void ExpandShapedJson(
VocShaper* shaper, CollectionNameResolver const* resolver,
TRI_voc_cid_t const& cid, TRI_doc_mptr_t const* mptr, VPackBuilder& b,
bool keepTopLevelOpen,
std::unordered_set<std::string> const& forbidden) {
b.add(VPackValue(VPackValueType::Object));
TRI_df_marker_t const* marker =
static_cast<TRI_df_marker_t const*>(mptr->getDataPtr());
TRI_shaped_json_t shaped;
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, marker);
std::shared_ptr<VPackBuilder> tmp = TRI_VelocyPackShapedJson(shaper, &shaped);
// Copy the shaped into our local builder
for (auto const& it : VPackObjectIterator(tmp->slice())) {
std::string key = it.key.copyString();
if (forbidden.count(key) == 0) {
b.add(it.key.copyString(), it.value);
}
}
char const* key = TRI_EXTRACT_MARKER_KEY(marker);
std::string id(resolver->getCollectionName(cid));
id.push_back('/');
id.append(key);
if (forbidden.count(TRI_VOC_ATTRIBUTE_ID) == 0) {
b.add(TRI_VOC_ATTRIBUTE_ID, VPackValue(id));
}
if (forbidden.count(TRI_VOC_ATTRIBUTE_REV) == 0) {
b.add(TRI_VOC_ATTRIBUTE_REV,
VPackValue(std::to_string(TRI_EXTRACT_MARKER_RID(marker))));
}
if (forbidden.count(TRI_VOC_ATTRIBUTE_KEY) == 0) {
b.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
}
#if 0
// TODO
if (TRI_IS_EDGE_MARKER(marker)) {
if (forbidden.count(TRI_VOC_ATTRIBUTE_FROM) == 0) {
std::string from(resolver->getCollectionNameCluster(
TRI_EXTRACT_MARKER_FROM_CID(marker)));
from.push_back('/');
from.append(TRI_EXTRACT_MARKER_FROM_KEY(marker));
b.add(TRI_VOC_ATTRIBUTE_FROM, VPackValue(from));
}
if (forbidden.count(TRI_VOC_ATTRIBUTE_TO) == 0) {
std::string to(
resolver->getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(marker)));
to.push_back('/');
to.append(TRI_EXTRACT_MARKER_TO_KEY(marker));
b.add(TRI_VOC_ATTRIBUTE_TO, VPackValue(to));
}
}
#endif
if (!keepTopLevelOpen) {
b.close();
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Reads a document by cid and key
/// Also lazy locks the collection.
/// Returns null if the document does not exist
////////////////////////////////////////////////////////////////////////////////
static void ReadDocument(arangodb::AqlTransaction* trx,
CollectionNameResolver const* resolver,
TRI_voc_cid_t cid, char const* key,
VPackBuilder& result) {
trx->addCollectionAtRuntime(cid);
OperationOptions options;
VPackSlice slice;
#warning fill slice from key
OperationResult opRes = trx->document(trx->collectionName(cid), slice, options);
#warning fill mptr
if (opRes.code != TRI_ERROR_NO_ERROR) {
result.add(VPackValue(VPackValueType::Null));
} else {
#warning convert opRes result to vpack external
result.add(VPackValue(static_cast<void const*>(nullptr), VPackValueType::External));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief function to filter the given list of mptr
////////////////////////////////////////////////////////////////////////////////
static void FilterDocuments(arangodb::ExampleMatcher const* matcher,
TRI_voc_cid_t cid,
std::vector<TRI_doc_mptr_t>& toFilter) {
if (matcher == nullptr) {
return;
}
size_t resultCount = toFilter.size();
for (size_t i = 0; i < resultCount; /* nothing */) {
if (!matcher->matches(cid, &toFilter[i])) {
toFilter.erase(toFilter.begin() + i);
--resultCount;
} else {
++i;
}
}
}
static void RequestEdges(VPackSlice const& vertexSlice,
arangodb::AqlTransaction* trx,
CollectionNameResolver const* resolver,
VocShaper* shaper, TRI_voc_cid_t cid,
TRI_document_collection_t* collection,
std::string const& collectionName,
std::string const& indexId,
TRI_edge_direction_e direction,
arangodb::ExampleMatcher const* matcher,
bool includeVertices, VPackBuilder& result) {
@ -571,59 +471,109 @@ static void RequestEdges(VPackSlice const& vertexSlice,
vertexId);
}
TRI_voc_cid_t startCid = resolver->getCollectionIdLocal(parts[0]);
if (startCid == 0) {
if (trx->getCollectionType(parts[0]) == TRI_COL_TYPE_UNKNOWN) {
THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'",
parts[0].c_str());
}
char* key = const_cast<char*>(parts[1].c_str());
std::vector<TRI_doc_mptr_t> edges = TRI_LookupEdgesDocumentCollection(
trx, collection, direction, startCid, key);
FilterDocuments(matcher, cid, edges);
size_t resultCount = edges.size();
VPackBuilder searchValueBuilder;
searchValueBuilder.openArray();
switch (direction) {
case TRI_EDGE_OUT:
searchValueBuilder.openArray();
searchValueBuilder.openObject();
searchValueBuilder.add(TRI_SLICE_KEY_EQUAL, VPackValue(vertexId));
searchValueBuilder.close();
searchValueBuilder.close();
searchValueBuilder.add(VPackValue(VPackValueType::None));
break;
case TRI_EDGE_IN:
searchValueBuilder.add(VPackValue(VPackValueType::None));
searchValueBuilder.openArray();
searchValueBuilder.openObject();
searchValueBuilder.add(TRI_SLICE_KEY_EQUAL, VPackValue(vertexId));
searchValueBuilder.close();
searchValueBuilder.close();
break;
case TRI_EDGE_ANY:
searchValueBuilder.openArray();
searchValueBuilder.openObject();
searchValueBuilder.add(TRI_SLICE_KEY_EQUAL, VPackValue(vertexId));
searchValueBuilder.close();
searchValueBuilder.close();
searchValueBuilder.openArray();
searchValueBuilder.openObject();
searchValueBuilder.add(TRI_SLICE_KEY_EQUAL, VPackValue(vertexId));
searchValueBuilder.close();
searchValueBuilder.close();
}
searchValueBuilder.close();
VPackSlice search = searchValueBuilder.slice();
OperationCursor cursor = trx->indexScan(
collectionName, arangodb::Transaction::CursorType::INDEX, indexId,
search, 0, UINT64_MAX, 1000, false);
if (cursor.failed()) {
THROW_ARANGO_EXCEPTION(cursor.code);
}
if (includeVertices) {
for (size_t i = 0; i < resultCount; ++i) {
VPackObjectBuilder guard(&result);
result.add(VPackValue("edge"));
std::unordered_set<std::string> unused;
#warning convert to vpack
ExpandShapedJson(shaper, resolver, cid, &(edges[i]), result, false, unused);
char const* targetKey = nullptr;
TRI_voc_cid_t targetCid = 0;
while (cursor.hasMore()) {
cursor.getMore();
VPackSlice edges = cursor.slice();
TRI_ASSERT(edges.isArray());
if (includeVertices) {
for (auto const& edge : VPackArrayIterator(edges)) {
VPackObjectBuilder guard(&result);
if (matcher->matches(edge)) {
result.add("edge", edge);
switch (direction) {
case TRI_EDGE_OUT:
targetKey = TRI_EXTRACT_MARKER_TO_KEY(&edges[i]);
targetCid = TRI_EXTRACT_MARKER_TO_CID(&edges[i]);
break;
case TRI_EDGE_IN:
targetKey = TRI_EXTRACT_MARKER_FROM_KEY(&edges[i]);
targetCid = TRI_EXTRACT_MARKER_FROM_CID(&edges[i]);
break;
case TRI_EDGE_ANY:
targetKey = TRI_EXTRACT_MARKER_TO_KEY(&edges[i]);
targetCid = TRI_EXTRACT_MARKER_TO_CID(&edges[i]);
if (targetCid == startCid && strcmp(targetKey, key) == 0) {
targetKey = TRI_EXTRACT_MARKER_FROM_KEY(&edges[i]);
targetCid = TRI_EXTRACT_MARKER_FROM_CID(&edges[i]);
std::string target;
TRI_ASSERT(edge.hasKey(TRI_VOC_ATTRIBUTE_FROM));
TRI_ASSERT(edge.hasKey(TRI_VOC_ATTRIBUTE_TO));
switch (direction) {
case TRI_EDGE_OUT:
target = edge.get(TRI_VOC_ATTRIBUTE_TO).copyString();
break;
case TRI_EDGE_IN:
target = edge.get(TRI_VOC_ATTRIBUTE_FROM).copyString();
break;
case TRI_EDGE_ANY:
target = edge.get(TRI_VOC_ATTRIBUTE_TO).copyString();
if (target == vertexId) {
target = edge.get(TRI_VOC_ATTRIBUTE_FROM).copyString();
}
break;
}
break;
}
if (targetKey == nullptr || targetCid == 0) {
// somehow invalid
continue;
if (target.empty()) {
// somehow invalid
continue;
}
std::vector<std::string> split = arangodb::basics::StringUtils::split(target, "/");
TRI_ASSERT(split.size() == 2);
VPackBuilder vertexSearch;
vertexSearch.openObject();
vertexSearch.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(split[1]));
vertexSearch.close();
OperationOptions opts;
OperationResult vertexResult = trx->document(split[0], vertexSearch.slice(), opts);
if (vertexResult.failed()) {
if (vertexResult.code == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
// This is okay
result.add("vertex", VPackValue(VPackValueType::Null));
} else {
THROW_ARANGO_EXCEPTION(vertexResult.code);
}
} else {
result.add("vertex", vertexResult.slice());
}
}
}
} else {
for (auto const& edge : VPackArrayIterator(edges)) {
if (matcher->matches(edge)) {
result.add(edge);
}
}
result.add(VPackValue("vertex"));
ReadDocument(trx, resolver, targetCid, targetKey, result);
}
} else {
for (size_t i = 0; i < resultCount; ++i) {
#warning convert to vpack
// ExpandShapedJson(shaper, resolver, cid, &(edges[i]), result, false, unused);
}
}
}
@ -655,6 +605,108 @@ static void UnsetOrKeep(VPackSlice const& value,
}
}
static void RegisterCollectionInTransaction(
arangodb::AqlTransaction* trx, std::string const& collectionName,
TRI_voc_cid_t& cid) {
cid = trx->resolver()->getCollectionIdLocal(collectionName);
if (cid == 0) {
THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'",
collectionName.c_str());
}
trx->addCollectionAtRuntime(cid);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Helper function to get a document by it's identifier
/// Lazy Locks the collection if necessary.
////////////////////////////////////////////////////////////////////////////////
static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx,
std::string const& collectionName,
std::string const& identifier,
bool ignoreError,
VPackBuilder& result) {
OperationOptions options;
OperationResult opRes;
VPackBuilder searchBuilder;
searchBuilder.openObject();
searchBuilder.add(VPackValue(TRI_VOC_ATTRIBUTE_KEY));
std::vector<std::string> parts =
arangodb::basics::StringUtils::split(identifier, "/");
if (parts.size() == 1) {
searchBuilder.add(VPackValue(identifier));
searchBuilder.close();
try {
TRI_voc_cid_t cid;
RegisterCollectionInTransaction(trx, collectionName, cid);
} catch (arangodb::basics::Exception const& ex) {
if (ignoreError) {
return;
}
throw;
}
opRes = trx->document(collectionName, searchBuilder.slice(), options);
} else if (parts.size() == 2) {
if (collectionName.empty()) {
searchBuilder.add(VPackValue(parts[1]));
searchBuilder.close();
try {
TRI_voc_cid_t cid;
RegisterCollectionInTransaction(trx, parts[0], cid);
} catch (arangodb::basics::Exception const& ex) {
if (ignoreError) {
return;
}
throw;
}
opRes = trx->document(parts[0], searchBuilder.slice(), options);
} else if (parts[0] != collectionName) {
// Reqesting an _id that cannot be stored in this collection
if (ignoreError) {
return;
}
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST);
} else {
searchBuilder.add(VPackValue(parts[1]));
searchBuilder.close();
try {
TRI_voc_cid_t cid;
RegisterCollectionInTransaction(trx, collectionName, cid);
} catch (arangodb::basics::Exception const& ex) {
if (ignoreError) {
return;
}
throw;
}
opRes = trx->document(collectionName, searchBuilder.slice(), options);
}
} else {
if (ignoreError) {
return;
}
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
}
if (opRes.failed()) {
if (ignoreError) {
return;
}
THROW_ARANGO_EXCEPTION(opRes.code);
}
result.add(opRes.slice());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Helper function to merge given parameters
/// Works for an array of objects as first parameter or arbitrary many
@ -732,63 +784,25 @@ static AqlValue$ MergeParameters(arangodb::aql::Query* query,
return AqlValue$(b);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Transforms VertexId to VelocyPack
////////////////////////////////////////////////////////////////////////////////
static void VertexIdToVPack(arangodb::AqlTransaction* trx,
CollectionNameResolver const* resolver,
VertexId const& id,
VPackBuilder& b) {
trx->addCollectionAtRuntime(id.cid);
OperationOptions options;
VPackSlice slice;
#warning fill slice from id.key
OperationResult opRes = trx->document(trx->collectionName(id.cid), slice, options);
#warning fill mptr
int res = opRes.code;
if (res != TRI_ERROR_NO_ERROR) {
if (res == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
b.add(VPackValue(VPackValueType::Null));
return;
}
THROW_ARANGO_EXCEPTION(res);
}
#warning convert to vpack
b.add(VPackValue(static_cast<void const*>(nullptr), VPackValueType::External));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Transforms VertexId to std::string
////////////////////////////////////////////////////////////////////////////////
static std::string VertexIdToString(CollectionNameResolver const* resolver,
VertexId const& id) {
return resolver->getCollectionName(id.cid) + "/" + std::string(id.key);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Transforms an unordered_map<VertexId> to AQL VelocyPack values
////////////////////////////////////////////////////////////////////////////////
static AqlValue$ VertexIdsToAqlValueVPack(
arangodb::aql::Query* query, arangodb::AqlTransaction* trx,
CollectionNameResolver const* resolver, std::unordered_set<VertexId>& ids,
bool includeData = false) {
static AqlValue$ VertexIdsToAqlValueVPack(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
std::unordered_set<std::string>& ids,
bool includeData = false) {
std::shared_ptr<VPackBuilder> result = query->getSharedBuilder();
{
VPackArrayBuilder b(result.get());
if (includeData) {
for (auto& it : ids) {
VertexIdToVPack(trx, resolver, it, *result);
// THROWS ERRORS if the Document was not found
GetDocumentByIdentifier(trx, "", it, false, *result);
}
} else {
for (auto& it : ids) {
result->add(VPackValue(VertexIdToString(resolver, it)));
result->add(VPackValue(it));
}
}
}
@ -832,12 +846,9 @@ static arangodb::Index* getGeoIndex(arangodb::AqlTransaction* trx,
}
static AqlValue$ buildGeoResult(arangodb::aql::Query* query,
GeoCoordinates* cors, VocShaper* shaper,
CollectionNameResolver const* resolver,
GeoCoordinates* cors,
TRI_voc_cid_t const& cid,
std::string const& attributeName) {
// TODO FIXME
// note: shaper will always be nullptr here...
if (cors == nullptr) {
std::shared_ptr<VPackBuilder> b = query->getSharedBuilder();
{
@ -892,19 +903,22 @@ static AqlValue$ buildGeoResult(arangodb::aql::Query* query,
try {
VPackArrayBuilder guard(b.get());
std::unordered_set<std::string> forbidden;
bool saveAttr = !attributeName.empty();
if (saveAttr) {
forbidden.emplace(attributeName);
}
for (auto& it : distances) {
#warning convert to vpack
ExpandShapedJson(shaper, resolver, cid, it._mptr, *b,
saveAttr, forbidden);
if (saveAttr) {
// The Object is Open and attributeName is not set
if (!attributeName.empty()) {
// We have to copy the entire document
for (auto& it : distances) {
VPackObjectBuilder docGuard(b.get());
b->add(attributeName, VPackValue(it._distance));
b->close();
VPackSlice doc(it._mptr->vpack());
for (auto const& entry : VPackObjectIterator(doc)) {
std::string key = entry.key.copyString();
if (key != attributeName) {
b->add(key, entry.value);
}
}
}
} else {
for (auto& it : distances) {
InsertMasterPointer(it._mptr, *b);
}
}
} catch (...) {
@ -2332,7 +2346,7 @@ AqlValue$ Functions::Neighbors(arangodb::aql::Query* query,
if (n > 4) {
auto edgeExamples = ExtractFunctionParameter(trx, parameters, 4);
if (!(edgeExamples.isArray() && edgeExamples.length() == 0)) {
opts.addEdgeFilter(edgeExamples, eci->getShaper(), eCid, resolver);
opts.addEdgeFilter(edgeExamples, eCid);
}
}
@ -2349,10 +2363,10 @@ AqlValue$ Functions::Neighbors(arangodb::aql::Query* query,
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
std::unordered_set<VertexId> neighbors;
TRI_RunNeighborsSearch(edgeCollectionInfos, opts, neighbors);
std::unordered_set<std::string> neighbors;
#warning TRI_RunNeighborsSearch(edgeCollectionInfos, opts, neighbors);
return VertexIdsToAqlValueVPack(query, trx, resolver, neighbors, includeData);
return VertexIdsToAqlValueVPack(query, trx, neighbors, includeData);
}
////////////////////////////////////////////////////////////////////////////////
@ -2426,7 +2440,7 @@ AqlValue$ Functions::Near(arangodb::aql::Query* query,
trx, latitude.getNumericValue<double>(),
longitude.getNumericValue<double>(), limitValue);
return buildGeoResult(query, cors, nullptr, resolver, cid, attributeName);
return buildGeoResult(query, cors, cid, attributeName);
}
////////////////////////////////////////////////////////////////////////////////
@ -2488,7 +2502,7 @@ AqlValue$ Functions::Within(arangodb::aql::Query* query,
trx, latitude.getNumericValue<double>(),
longitude.getNumericValue<double>(), radius.getNumericValue<double>());
return buildGeoResult(query, cors, nullptr, resolver, cid, attributeName);
return buildGeoResult(query, cors, cid, attributeName);
}
////////////////////////////////////////////////////////////////////////////////
@ -2693,104 +2707,6 @@ AqlValue$ Functions::Minus(arangodb::aql::Query* query,
return AqlValue$(b.get());
}
static void RegisterCollectionInTransaction(
arangodb::AqlTransaction* trx, std::string const& collectionName,
TRI_voc_cid_t& cid) {
cid = trx->resolver()->getCollectionIdLocal(collectionName);
if (cid == 0) {
THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'",
collectionName.c_str());
}
trx->addCollectionAtRuntime(cid);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Helper function to get a document by it's identifier
/// The collection has to be locked by the transaction before
////////////////////////////////////////////////////////////////////////////////
static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx,
std::string const& collectionName,
std::string const& identifier,
VPackBuilder& result) {
OperationOptions options;
std::vector<std::string> parts =
arangodb::basics::StringUtils::split(identifier, "/");
if (parts.size() == 1) {
VPackSlice slice;
#warning fill slice from parts[0]
OperationResult opRes = trx->document(collectionName, slice, options);
#warning fill mptr
if (!opRes.successful()) {
return;
}
} else if (parts.size() == 2) {
if (parts[0] != collectionName) {
// Reqesting an _id that cannot be stored in this collection
return;
}
VPackSlice slice;
#warning fill slice from parts[1]
OperationResult opRes = trx->document(collectionName, slice, options);
#warning fill mptr
if (!opRes.successful()) {
return;
}
} else {
return;
}
#warning convert to vpack
result.add(VPackValue(static_cast<void const*>(nullptr), VPackValueType::External));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Helper function to get a document by its _id
/// This function will lazy read-lock the collection.
/// this function will not throw if the document or the collection cannot be
/// found
////////////////////////////////////////////////////////////////////////////////
static void GetDocumentByIdentifier(arangodb::AqlTransaction* trx,
std::string const& identifier,
VPackBuilder& result) {
std::vector<std::string> parts =
arangodb::basics::StringUtils::split(identifier, "/");
if (parts.size() != 2) {
return;
}
std::string collectionName = parts[0];
TRI_voc_cid_t cid = 0;
try {
RegisterCollectionInTransaction(trx, collectionName, cid);
} catch (arangodb::basics::Exception const& ex) {
// don't throw if collection is not found
if (ex.code() == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
return;
}
throw;
}
OperationOptions options;
VPackSlice slice;
#warning fill slice from parts[1]
OperationResult opRes = trx->document(collectionName, slice, options);
#warning fill mptr
if (opRes.code != TRI_ERROR_NO_ERROR) {
return;
}
#warning convert opRes result to vpack external
result.add(VPackValue(static_cast<void const*>(nullptr), VPackValueType::External));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief function Document
////////////////////////////////////////////////////////////////////////////////
@ -2811,7 +2727,7 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
std::shared_ptr<VPackBuilder> b = query->getSharedBuilder();
if (id.isString()) {
std::string identifier = id.copyString();
GetDocumentByIdentifier(trx, identifier, *b);
GetDocumentByIdentifier(trx, "", identifier, true, *b);
if (b->isEmpty()) {
// not found
b->add(VPackValue(VPackValueType::Null));
@ -2819,13 +2735,9 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
} else if (id.isArray()) {
VPackArrayBuilder guard(b.get());
for (auto const& next : VPackArrayIterator(id)) {
try {
if (next.isString()) {
std::string identifier = next.copyString();
GetDocumentByIdentifier(trx, identifier, *b);
}
} catch (arangodb::basics::Exception const&) {
// Ignore all ArangoDB exceptions here
if (next.isString()) {
std::string identifier = next.copyString();
GetDocumentByIdentifier(trx, "", identifier, true, *b);
}
}
} else {
@ -2840,19 +2752,8 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
}
std::string collectionName = collectionSlice.copyString();
TRI_voc_cid_t cid;
bool notFound = false;
try {
RegisterCollectionInTransaction(trx, collectionName, cid);
} catch (arangodb::basics::Exception const& ex) {
// don't throw if collection is not found
if (ex.code() != TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
throw;
}
notFound = true;
}
VPackSlice id = ExtractFunctionParameter(trx, parameters, 1);
if (id.isString()) {
if (notFound) {
@ -2862,7 +2763,7 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
}
std::shared_ptr<VPackBuilder> b = query->getSharedBuilder();
std::string identifier = id.copyString();
GetDocumentByIdentifier(trx, collectionName, identifier, *b);
GetDocumentByIdentifier(trx, collectionName, identifier, true, *b);
if (b->isEmpty()) {
b->add(VPackValue(VPackValueType::Null));
}
@ -2873,13 +2774,9 @@ AqlValue$ Functions::Document(arangodb::aql::Query* query,
VPackArrayBuilder guard(b.get());
if (!notFound) {
for (auto const& next : VPackArrayIterator(id)) {
try {
if (next.isString()) {
std::string identifier = next.copyString();
GetDocumentByIdentifier(trx, collectionName, identifier, *b);
}
} catch (arangodb::basics::Exception const&) {
// Ignore all ArangoDB exceptions here
if (next.isString()) {
std::string identifier = next.copyString();
GetDocumentByIdentifier(trx, collectionName, identifier, true, *b);
}
}
}
@ -2916,7 +2813,6 @@ AqlValue$ Functions::Edges(arangodb::aql::Query* query,
TRI_voc_cid_t cid;
RegisterCollectionInTransaction(trx, collectionName, cid);
TRI_document_collection_t* documentCollection = trx->documentCollection(cid);
if (!trx->isEdgeCollection(collectionName)) {
RegisterWarning(query, "EDGES", TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID);
@ -2964,18 +2860,20 @@ AqlValue$ Functions::Edges(arangodb::aql::Query* query,
return AqlValue$(b.get());
}
auto resolver = trx->resolver();
auto shaper = documentCollection->getShaper();
std::unique_ptr<arangodb::ExampleMatcher> matcher;
TRI_document_collection_t* documentCollection = trx->documentCollection(cid);
arangodb::EdgeIndex* edgeIndex = documentCollection->edgeIndex();
TRI_ASSERT(edgeIndex != nullptr); // Checked because collection is edge Collection.
std::string indexId = arangodb::basics::StringUtils::itoa(edgeIndex->id());
if (n > 3) {
// We might have examples
VPackSlice exampleSlice = ExtractFunctionParameter(trx, parameters, 3);
if ((exampleSlice.isArray() && exampleSlice.length() != 0)|| exampleSlice.isObject()) {
try {
matcher.reset(
new arangodb::ExampleMatcher(exampleSlice, resolver, false));
new arangodb::ExampleMatcher(exampleSlice, false));
} catch (arangodb::basics::Exception const& e) {
if (e.code() != TRI_RESULT_ELEMENT_NOT_FOUND) {
throw;
@ -3008,16 +2906,14 @@ AqlValue$ Functions::Edges(arangodb::aql::Query* query,
if (vertexSlice.isArray()) {
for (auto const& v : VPackArrayIterator(vertexSlice)) {
try {
RequestEdges(v, trx, resolver, shaper, cid,
documentCollection, direction,
RequestEdges(v, trx, collectionName, indexId, direction,
matcher.get(), includeVertices, *b);
} catch (...) {
// Errors in Array are simply ignored
}
}
} else {
RequestEdges(vertexSlice, trx, resolver, shaper, cid,
documentCollection, direction,
RequestEdges(vertexSlice, trx, collectionName, indexId, direction,
matcher.get(), includeVertices, *b);
}
}
@ -4309,7 +4205,6 @@ AqlValue$ Functions::Fulltext(arangodb::aql::Query* query,
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
}
auto shaper = document->getShaper();
size_t const numResults = queryResult->_numDocuments;
std::shared_ptr<VPackBuilder> b = query->getSharedBuilder();
@ -4317,11 +4212,8 @@ AqlValue$ Functions::Fulltext(arangodb::aql::Query* query,
VPackArrayBuilder guard(b.get());
for (size_t i = 0; i < numResults; ++i) {
std::unordered_set<std::string> unused;
#warning convert to vpack
ExpandShapedJson(shaper, resolver, cid,
(TRI_doc_mptr_t const*)queryResult->_documents[i], *b,
false, unused);
InsertMasterPointer((TRI_doc_mptr_t const*)queryResult->_documents[i],
*b);
}
} catch (...) {
TRI_FreeResultFulltextIndex(queryResult);

View File

@ -668,8 +668,7 @@ class PropagateConstantAttributesHelper {
return;
}
if (TRI_CompareValuesJson(value->computeJson(), previous->computeJson(),
true) != 0) {
if (!value->computeValue().equals(previous->computeValue())) {
// different value found for an already tracked attribute. better not
// use this attribute
(*it2).second = nullptr;

View File

@ -241,6 +241,31 @@ void EdgeIndexIterator::reset() {
_buffer = nullptr;
}
TRI_doc_mptr_t* AnyDirectionEdgeIndexIterator::next() {
TRI_doc_mptr_t* res = nullptr;
if (_useInbound) {
do {
res = _inbound->next();
} while (res != nullptr && _seen.find(res) != _seen.end());
return res;
}
res = _outbound->next();
if (res == nullptr) {
_useInbound = true;
return next();
}
_seen.emplace(res);
return res;
}
void AnyDirectionEdgeIndexIterator::reset() {
_useInbound = false;
_seen.clear();
_outbound->reset();
_inbound->reset();
}
EdgeIndex::EdgeIndex(TRI_idx_iid_t iid, TRI_document_collection_t* collection)
: Index(iid, collection,
std::vector<std::vector<arangodb::basics::AttributeName>>(
@ -529,6 +554,52 @@ arangodb::aql::AstNode* EdgeIndex::specializeCondition(
return matcher.specializeOne(this, node, reference);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates an IndexIterator for the given VelocyPackSlices.
/// The searchValue is a an Array with exactly two Entries.
/// If the first is set it means we are searching for _from (OUTBOUND),
/// if the second is set we are searching for _to (INBOUND).
/// if both are set we are search for ANY direction. Result is made
/// DISTINCT.
/// Each defined slice that is set has to be list of keys to search for.
/// Each key needs to have the following formats:
///
/// 1) {"eq": <compareValue>} // The value in index is exactly this
///
/// Reverse is not supported, hence ignored
/// NOTE: The iterator is only valid as long as the slice points to
/// a valid memory region.
////////////////////////////////////////////////////////////////////////////////
IndexIterator* EdgeIndex::iteratorForSlice(
arangodb::Transaction* trx, IndexIteratorContext*,
arangodb::velocypack::Slice const searchValues, bool) const {
if (!searchValues.isArray() || searchValues.length() != 2) {
// Invalid searchValue
return nullptr;
}
VPackSlice const from = searchValues.at(0);
VPackSlice const to = searchValues.at(1);
if (!from.isNone()) {
TRI_ASSERT(from.isArray());
if (!to.isNone()) {
// ANY search
TRI_ASSERT(to.isArray());
auto left = std::make_unique<EdgeIndexIterator>(trx, _edgesFrom, from);
auto right = std::make_unique<EdgeIndexIterator>(trx, _edgesTo, to);
return new AnyDirectionEdgeIndexIterator(left.release(), right.release());
}
// OUTBOUND search
TRI_ASSERT(to.isNone());
return new EdgeIndexIterator(trx, _edgesFrom, from);
} else {
// INBOUND search
TRI_ASSERT(to.isArray());
return new EdgeIndexIterator(trx, _edgesTo, to);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create the iterator
////////////////////////////////////////////////////////////////////////////////

View File

@ -58,6 +58,20 @@ class EdgeIndexIterator final : public IndexIterator {
_batchSize(50) { // This might be adjusted
}
EdgeIndexIterator(arangodb::Transaction* trx,
TRI_EdgeIndexHash_t const* index,
arangodb::velocypack::Slice searchValues)
: _trx(trx),
_index(index),
_searchValues(nullptr),
_keys(searchValues),
_position(0),
_last(nullptr),
_buffer(nullptr),
_posInBuffer(0),
_batchSize(50) { // This might be adjusted
}
~EdgeIndexIterator() {
// Free the vector space, not the content
delete _buffer;
@ -75,6 +89,32 @@ class EdgeIndexIterator final : public IndexIterator {
size_t _batchSize;
};
class AnyDirectionEdgeIndexIterator final : public IndexIterator {
public:
TRI_doc_mptr_t* next() override;
void reset() override;
AnyDirectionEdgeIndexIterator(EdgeIndexIterator* outboundIterator,
EdgeIndexIterator* inboundIterator)
: _outbound(outboundIterator),
_inbound(inboundIterator),
_useInbound(false),
_done(false) {}
~AnyDirectionEdgeIndexIterator() {
delete _outbound;
delete _inbound;
}
private:
EdgeIndexIterator* _outbound;
EdgeIndexIterator* _inbound;
std::unordered_set<TRI_doc_mptr_t*> _seen;
bool _useInbound;
bool _done;
};
class EdgeIndex final : public Index {
public:
EdgeIndex() = delete;
@ -152,6 +192,26 @@ class EdgeIndex final : public Index {
arangodb::aql::AstNode* specializeCondition(
arangodb::aql::AstNode*, arangodb::aql::Variable const*) const override;
////////////////////////////////////////////////////////////////////////////////
/// @brief creates an IndexIterator for the given VelocyPackSlices.
/// The searchValue is a an Array with exactly two Entries, one of them
/// has to be NONE.
/// If the first is set it means we are searching for _from (OUTBOUND),
/// if the second is set we are searching for _to (INBOUND).
/// The slice that is set has to be list of keys to search for.
/// Each key needs to have the following formats:
///
/// 1) {"eq": <compareValue>} // The value in index is exactly this
///
/// Reverse is not supported, hence ignored
/// NOTE: The iterator is only valid as long as the slice points to
/// a valid memory region.
////////////////////////////////////////////////////////////////////////////////
IndexIterator* iteratorForSlice(arangodb::Transaction*, IndexIteratorContext*,
arangodb::velocypack::Slice const,
bool) const override;
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief create the iterator

View File

@ -594,7 +594,7 @@ OperationResult Transaction::documentLocal(std::string const& collectionName,
}
if (!options.silent) {
resultBuilder.add(VPackSlice(mptr.vpack()));
resultBuilder.add(VPackValue(static_cast<void const*>(mptr.vpack()), VPackValueType::External));
}
return TRI_ERROR_NO_ERROR;
@ -1584,7 +1584,7 @@ OperationCursor Transaction::indexScan(
std::string const& indexId, VPackSlice const search,
uint64_t skip, uint64_t limit, uint64_t batchSize, bool reverse) {
// TODO Who checks if indexId is valid and is used for this collection?
#warning TODO Who checks if indexId is valid and is used for this collection?
// For now we assume indexId is the iid part of the index.
if (ServerState::instance()->isCoordinator()) {

View File

@ -248,13 +248,12 @@ bool BasicOptions::matchesVertex(VertexId const& v) const {
// OperationResult opRes = trx->document(it->second.col, slice, options);
OperationResult opRes(TRI_ERROR_INTERNAL);
#warning fill vertex
TRI_doc_mptr_t vertex;
if (!opRes.successful()) {
return false;
}
return it->second.matcher->matches(v.cid, &vertex);
return it->second.matcher->matches(opRes.slice());
}
////////////////////////////////////////////////////////////////////////////////
@ -302,13 +301,12 @@ void BasicOptions::addEdgeFilter(Json const& example, VocShaper* shaper,
/// @brief Insert a new edge matcher object
////////////////////////////////////////////////////////////////////////////////
void BasicOptions::addEdgeFilter(VPackSlice const& example, VocShaper* shaper,
TRI_voc_cid_t const& cid,
CollectionNameResolver const* resolver) {
void BasicOptions::addEdgeFilter(VPackSlice const& example,
TRI_voc_cid_t const& cid) {
useEdgeFilter = true;
auto it = _edgeFilter.find(cid);
if (it == _edgeFilter.end()) {
_edgeFilter.emplace(cid, new ExampleMatcher(example, resolver, true));
_edgeFilter.emplace(cid, new ExampleMatcher(example, true));
}
}
@ -332,7 +330,7 @@ bool BasicOptions::matchesEdge(EdgeId& e, TRI_doc_mptr_t* edge) const {
return false;
}
return it->second->matches(e.cid, edge);
return it->second->matches(VPackSlice(edge->vpack()));
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -121,9 +121,8 @@ struct BasicOptions {
TRI_voc_cid_t const& cid,
arangodb::CollectionNameResolver const* resolver);
void addEdgeFilter(arangodb::velocypack::Slice const& example, VocShaper* shaper,
TRI_voc_cid_t const& cid,
arangodb::CollectionNameResolver const* resolver);
void addEdgeFilter(arangodb::velocypack::Slice const& example,
TRI_voc_cid_t const& cid);
void addVertexFilter(v8::Isolate* isolate,
v8::Handle<v8::Value> const& example,

View File

@ -75,7 +75,7 @@ void ExampleMatcher::fillExampleDefinition(
}
void ExampleMatcher::fillExampleDefinition(
VPackSlice const& example, CollectionNameResolver const* resolver,
VPackSlice const& example,
ExampleDefinition& def) {
TRI_ASSERT(def._values.isEmpty());
VPackArrayBuilder guard(&def._values);
@ -166,11 +166,10 @@ ExampleMatcher::ExampleMatcher(TRI_json_t const* example,
////////////////////////////////////////////////////////////////////////////////
ExampleMatcher::ExampleMatcher(VPackSlice const& example,
CollectionNameResolver const* resolver,
bool allowStrings) {
if (example.isObject() || example.isString()) {
ExampleDefinition def;
ExampleMatcher::fillExampleDefinition(example, resolver, def);
ExampleMatcher::fillExampleDefinition(example, def);
definitions.emplace_back(std::move(def));
} else if (example.isArray()) {
for (auto const& e : VPackArrayIterator(example)) {
@ -179,7 +178,7 @@ ExampleMatcher::ExampleMatcher(VPackSlice const& example,
// We do not match strings in Array
continue;
}
ExampleMatcher::fillExampleDefinition(e, resolver, def);
ExampleMatcher::fillExampleDefinition(e, def);
definitions.emplace_back(std::move(def));
}
if (definitions.empty()) {
@ -190,16 +189,11 @@ ExampleMatcher::ExampleMatcher(VPackSlice const& example,
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the given mptr matches the examples in this class
/// @brief Checks if the given velocyPack matches the examples in this class
////////////////////////////////////////////////////////////////////////////////
bool ExampleMatcher::matches(TRI_voc_cid_t, TRI_doc_mptr_t const* mptr) const {
if (mptr == nullptr) {
return false;
}
VPackSlice toMatch(mptr->vpack());
bool ExampleMatcher::matches(VPackSlice const toMatch) const {
for (auto const& def : definitions) {
VPackSlice const compareValue = def.slice();
size_t i = 0;

View File

@ -29,8 +29,6 @@
#include <v8.h>
struct TRI_doc_mptr_t;
namespace arangodb {
namespace velocypack {
@ -50,7 +48,6 @@ class ExampleMatcher {
std::vector<ExampleDefinition> definitions;
void fillExampleDefinition(arangodb::velocypack::Slice const& example,
arangodb::CollectionNameResolver const* resolver,
ExampleDefinition& def);
void fillExampleDefinition(v8::Isolate* isolate,
@ -69,12 +66,11 @@ class ExampleMatcher {
arangodb::CollectionNameResolver const* resolver);
ExampleMatcher(arangodb::velocypack::Slice const& example,
arangodb::CollectionNameResolver const* resolver,
bool allowStrings);
~ExampleMatcher() { }
bool matches(TRI_voc_cid_t, TRI_doc_mptr_t const* mptr) const;
bool matches(arangodb::velocypack::Slice const) const;
};
}