mirror of https://gitee.com/bigwinds/arangodb
Aql by line mixed fixes (#8349)
This commit is contained in:
parent
a2ca779e71
commit
8d649903f7
|
@ -41,6 +41,7 @@ class ExecutionEngineResult {
|
|||
ExecutionEngineResult(int errorNumber, std::string&& errorMessage);
|
||||
|
||||
// This is not explicit on purpose
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
ExecutionEngineResult(Result const& result);
|
||||
explicit ExecutionEngineResult(ExecutionEngine*);
|
||||
|
|
|
@ -40,7 +40,10 @@ using namespace arangodb::aql;
|
|||
|
||||
CountCollectExecutorInfos::CountCollectExecutorInfos(
|
||||
RegisterId collectRegister, RegisterId nrInputRegisters,
|
||||
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
|
||||
RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep)
|
||||
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),
|
||||
make_shared_unordered_set({collectRegister}),
|
||||
|
|
|
@ -45,8 +45,10 @@ using namespace arangodb;
|
|||
using namespace arangodb::aql;
|
||||
|
||||
EnumerateCollectionExecutorInfos::EnumerateCollectionExecutorInfos(
|
||||
RegisterId outputRegister, RegisterId nrInputRegisters,
|
||||
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
|
||||
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
|
||||
Collection const* collection, Variable const* outVariable, bool produceResult,
|
||||
std::vector<std::string> const& projections, transaction::Methods* trxPtr,
|
||||
|
|
|
@ -40,7 +40,10 @@ using namespace arangodb::aql;
|
|||
|
||||
EnumerateListExecutorInfos::EnumerateListExecutorInfos(
|
||||
RegisterId inputRegister, RegisterId outputRegister, RegisterId nrInputRegisters,
|
||||
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
|
||||
RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep)
|
||||
: ExecutorInfos(make_shared_unordered_set({inputRegister}),
|
||||
make_shared_unordered_set({outputRegister}),
|
||||
|
|
|
@ -50,6 +50,7 @@ class SingleRowFetcher;
|
|||
|
||||
class EnumerateListExecutorInfos : public ExecutorInfos {
|
||||
public:
|
||||
// cppcheck-suppress passedByValue
|
||||
EnumerateListExecutorInfos(RegisterId inputRegister, RegisterId outputRegister,
|
||||
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
|
|
|
@ -24,10 +24,15 @@
|
|||
|
||||
using namespace arangodb::aql;
|
||||
|
||||
ExecutorInfos::ExecutorInfos(std::shared_ptr<std::unordered_set<RegisterId>> readableInputRegisters,
|
||||
ExecutorInfos::ExecutorInfos(
|
||||
// cppcheck-suppress passedByValue
|
||||
std::shared_ptr<std::unordered_set<RegisterId>> readableInputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::shared_ptr<std::unordered_set<RegisterId>> writeableOutputRegisters,
|
||||
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep)
|
||||
: _inRegs(std::move(readableInputRegisters)),
|
||||
_outRegs(std::move(writeableOutputRegisters)),
|
||||
|
|
|
@ -40,7 +40,9 @@ using namespace arangodb::aql;
|
|||
|
||||
FilterExecutorInfos::FilterExecutorInfos(RegisterId inputRegister, RegisterId nrInputRegisters,
|
||||
RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep)
|
||||
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(inputRegister),
|
||||
nullptr, nrInputRegisters, nrOutputRegisters,
|
||||
|
|
|
@ -32,7 +32,9 @@ using namespace arangodb;
|
|||
using namespace arangodb::aql;
|
||||
|
||||
IdExecutorInfos::IdExecutorInfos(RegisterId nrInOutRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> toKeep,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear)
|
||||
: ExecutorInfos(make_shared_unordered_set(), make_shared_unordered_set(),
|
||||
nrInOutRegisters, nrInOutRegisters,
|
||||
|
|
|
@ -56,6 +56,10 @@ void InAndOutRowExpressionContext::setInputRow(InputAqlItemRow input) {
|
|||
_input = input;
|
||||
}
|
||||
|
||||
void InAndOutRowExpressionContext::invalidateInputRow() {
|
||||
_input = InputAqlItemRow{CreateInvalidInputRowHint{}};
|
||||
}
|
||||
|
||||
AqlValue const& InAndOutRowExpressionContext::getRegisterValue(size_t i) const {
|
||||
TRI_ASSERT(_input.isInitialized());
|
||||
TRI_ASSERT(i < _regs.size());
|
||||
|
|
|
@ -49,6 +49,8 @@ class InAndOutRowExpressionContext final : public QueryExpressionContext {
|
|||
|
||||
void setInputRow(InputAqlItemRow input);
|
||||
|
||||
void invalidateInputRow();
|
||||
|
||||
size_t numRegisters() const override { return _regs.size(); }
|
||||
|
||||
AqlValue const& getRegisterValue(size_t i) const override;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include <lib/Logger/LogMacros.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using namespace arangodb;
|
||||
|
@ -65,8 +66,10 @@ static void resolveFCallConstAttributes(AstNode* fcall) {
|
|||
} // namespace
|
||||
|
||||
IndexExecutorInfos::IndexExecutorInfos(
|
||||
RegisterId outputRegister, RegisterId nrInputRegisters,
|
||||
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
|
||||
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
|
||||
Collection const* collection, Variable const* outVariable, bool produceResult,
|
||||
std::vector<std::string> const& projections, transaction::Methods* trxPtr,
|
||||
|
@ -80,7 +83,7 @@ IndexExecutorInfos::IndexExecutorInfos(
|
|||
make_shared_unordered_set({outputRegister}),
|
||||
nrInputRegisters, nrOutputRegisters,
|
||||
std::move(registersToClear), std::move(registersToKeep)),
|
||||
_indexes(indexes),
|
||||
_indexes(std::move(indexes)),
|
||||
_condition(condition),
|
||||
_ast(ast),
|
||||
_hasMultipleExpansions(false),
|
||||
|
@ -107,9 +110,10 @@ IndexExecutor::IndexExecutor(Fetcher& fetcher, Infos& infos)
|
|||
_allowCoveringIndexOptimization(false),
|
||||
_cursor(nullptr),
|
||||
_cursors(_infos.getIndexes().size()),
|
||||
_currentIndex(0),
|
||||
_alreadyReturned(),
|
||||
_indexesExhausted(false),
|
||||
_isLastIndex(false) {
|
||||
|
||||
TRI_ASSERT(!_infos.getIndexes().empty());
|
||||
|
||||
if (_infos.getCondition() != nullptr) {
|
||||
|
@ -340,7 +344,7 @@ void IndexExecutor::executeExpressions(InputAqlItemRow& input) {
|
|||
// The following are needed to evaluate expressions with local data from
|
||||
// the current incoming item:
|
||||
auto ast = _infos.getAst();
|
||||
AstNode* condition = const_cast<AstNode*>(_infos.getCondition());
|
||||
auto* condition = const_cast<AstNode*>(_infos.getCondition());
|
||||
|
||||
// modify the existing node in place
|
||||
TEMPORARILY_UNLOCK_NODE(condition);
|
||||
|
@ -435,7 +439,7 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
|
|||
}
|
||||
}
|
||||
TRI_ASSERT(_input.isInitialized());
|
||||
TRI_ASSERT(getCursor()->hasMore());
|
||||
TRI_ASSERT(getCursor() != nullptr && getCursor()->hasMore());
|
||||
|
||||
IndexIterator::DocumentCallback callback;
|
||||
|
||||
|
@ -473,10 +477,8 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
|
|||
TRI_ASSERT(!getIndexesExhausted());
|
||||
|
||||
// Read the next elements from the indexes
|
||||
// auto saveReturned = _infos.getReturned();
|
||||
bool more = readIndex(callback, hasWritten);
|
||||
// TRI_ASSERT(!more || _infos.getCursor()->hasMore());
|
||||
TRI_ASSERT((getCursor() != nullptr || !more) || (getCursor() != nullptr && more == getCursor()->hasMore()));
|
||||
TRI_ASSERT(getCursor() != nullptr || !more);
|
||||
|
||||
if (!more) {
|
||||
_input = InputAqlItemRow{CreateInvalidInputRowHint{}};
|
||||
|
|
|
@ -181,11 +181,10 @@ class IndexExecutor {
|
|||
typedef std::function<void(InputAqlItemRow&, OutputAqlItemRow&, arangodb::velocypack::Slice, RegisterId)> DocumentProducingFunction;
|
||||
|
||||
void setProducingFunction(DocumentProducingFunction documentProducer) {
|
||||
_documentProducer = documentProducer;
|
||||
_documentProducer = std::move(documentProducer);
|
||||
}
|
||||
|
||||
private:
|
||||
bool initializeCursor();
|
||||
bool advanceCursor();
|
||||
void executeExpressions(InputAqlItemRow& input);
|
||||
bool initIndexes(InputAqlItemRow& input);
|
||||
|
|
|
@ -58,7 +58,9 @@ class InputAqlItemRow {
|
|||
explicit InputAqlItemRow(CreateInvalidInputRowHint)
|
||||
: _blockShell(nullptr), _baseIndex(0) {}
|
||||
|
||||
InputAqlItemRow(std::shared_ptr<AqlItemBlockShell> blockShell, size_t baseIndex)
|
||||
InputAqlItemRow(
|
||||
// cppcheck-suppress passedByValue
|
||||
std::shared_ptr<AqlItemBlockShell> blockShell, size_t baseIndex)
|
||||
: _blockShell(std::move(blockShell)), _baseIndex(baseIndex) {
|
||||
TRI_ASSERT(_blockShell != nullptr);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ using namespace arangodb;
|
|||
using namespace arangodb::aql;
|
||||
|
||||
LimitExecutorInfos::LimitExecutorInfos(RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep,
|
||||
size_t offset, size_t limit, bool fullCount)
|
||||
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "Aql/InAndOutRowExpressionContext.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace arangodb {
|
||||
namespace velocypack {
|
||||
class Slice;
|
||||
|
@ -48,7 +50,8 @@ class PruneExpressionEvaluator {
|
|||
~PruneExpressionEvaluator();
|
||||
|
||||
bool evaluate();
|
||||
void prepareContext(InputAqlItemRow input) { _ctx.setInputRow(input); }
|
||||
void prepareContext(InputAqlItemRow input) { _ctx.setInputRow(std::move(input)); }
|
||||
void unPrepareContext() { _ctx.invalidateInputRow(); }
|
||||
|
||||
bool needsVertex() const { return _ctx.needsVertexValue(); }
|
||||
void injectVertex(velocypack::Slice v) { _ctx.setVertexValue(v); }
|
||||
|
|
|
@ -52,8 +52,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
|
|||
ReturnExecutorInfos(ReturnExecutorInfos const&) = delete;
|
||||
~ReturnExecutorInfos() = default;
|
||||
|
||||
Variable const& inVariable() const { return *_inVariable; }
|
||||
|
||||
RegisterId getInputRegisterId() const { return _inputRegisterId; }
|
||||
|
||||
RegisterId getOutputRegisterId() const {
|
||||
|
@ -68,7 +66,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
|
|||
|
||||
private:
|
||||
/// @brief the variable produced by Return
|
||||
Variable const* _inVariable;
|
||||
RegisterId _inputRegisterId;
|
||||
bool _doCount;
|
||||
bool _returnInheritedResults;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <velocypack/StringRef.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::aql;
|
||||
using namespace arangodb::graph;
|
||||
|
@ -55,7 +57,8 @@ ShortestPathExecutorInfos::ShortestPathExecutorInfos(
|
|||
std::unique_ptr<graph::ShortestPathFinder>&& finder,
|
||||
std::unordered_map<OutputName, RegisterId, OutputNameHash>&& registerMapping,
|
||||
InputVertex&& source, InputVertex&& target)
|
||||
: ExecutorInfos(inputRegisters, outputRegisters, nrInputRegisters, nrOutputRegisters,
|
||||
: ExecutorInfos(std::move(inputRegisters), std::move(outputRegisters),
|
||||
nrInputRegisters, nrOutputRegisters,
|
||||
std::move(registersToClear), std::move(registersToKeep)),
|
||||
_finder(std::move(finder)),
|
||||
_registerMapping(std::move(registerMapping)),
|
||||
|
|
|
@ -58,9 +58,11 @@ class ShortestPathExecutorInfos : public ExecutorInfos {
|
|||
RegisterId reg;
|
||||
std::string value;
|
||||
|
||||
InputVertex(std::string const value)
|
||||
: type(CONSTANT), reg(0), value(value) {}
|
||||
InputVertex(RegisterId reg) : type(REGISTER), reg(reg), value("") {}
|
||||
// cppcheck-suppress passedByValue
|
||||
explicit InputVertex(std::string value)
|
||||
: type(CONSTANT), reg(0), value(std::move(value)) {}
|
||||
explicit InputVertex(RegisterId reg)
|
||||
: type(REGISTER), reg(reg), value("") {}
|
||||
};
|
||||
|
||||
enum OutputName { VERTEX, EDGE };
|
||||
|
|
|
@ -72,21 +72,22 @@ static void parseNodeInput(AstNode const* node, std::string& id, Variable const*
|
|||
}
|
||||
static ShortestPathExecutorInfos::InputVertex prepareVertexInput(ShortestPathNode const* node,
|
||||
bool isTarget) {
|
||||
using InputVertex = ShortestPathExecutorInfos::InputVertex;
|
||||
if (isTarget) {
|
||||
if (node->usesTargetInVariable()) {
|
||||
auto it = node->getRegisterPlan()->varInfo.find(node->targetInVariable()->id);
|
||||
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
|
||||
return {it->second.registerId};
|
||||
return InputVertex{it->second.registerId};
|
||||
} else {
|
||||
return {node->getTargetVertex()};
|
||||
return InputVertex{node->getTargetVertex()};
|
||||
}
|
||||
} else {
|
||||
if (node->usesStartInVariable()) {
|
||||
auto it = node->getRegisterPlan()->varInfo.find(node->startInVariable()->id);
|
||||
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
|
||||
return {it->second.registerId};
|
||||
return InputVertex{it->second.registerId};
|
||||
} else {
|
||||
return {node->getStartVertex()};
|
||||
return InputVertex{node->getStartVertex()};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,12 +81,14 @@ static std::shared_ptr<std::unordered_set<RegisterId>> mapSortRegistersToRegiste
|
|||
return set;
|
||||
}
|
||||
|
||||
SortExecutorInfos::SortExecutorInfos(std::vector<SortRegister> sortRegisters,
|
||||
std::size_t limit, AqlItemBlockManager& manager,
|
||||
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
SortExecutorInfos::SortExecutorInfos(
|
||||
// cppcheck-suppress passedByValue
|
||||
std::vector<SortRegister> sortRegisters, std::size_t limit,
|
||||
AqlItemBlockManager& manager, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToClear,
|
||||
std::unordered_set<RegisterId> registersToKeep,
|
||||
transaction::Methods* trx, bool stable)
|
||||
// cppcheck-suppress passedByValue
|
||||
std::unordered_set<RegisterId> registersToKeep, transaction::Methods* trx, bool stable)
|
||||
: ExecutorInfos(mapSortRegistersToRegisterIds(sortRegisters), nullptr,
|
||||
nrInputRegisters, nrOutputRegisters,
|
||||
std::move(registersToClear), std::move(registersToKeep)),
|
||||
|
|
|
@ -116,7 +116,22 @@ TraversalExecutor::TraversalExecutor(Fetcher& fetcher, Infos& infos)
|
|||
_input{CreateInvalidInputRowHint{}},
|
||||
_rowState(ExecutionState::HASMORE),
|
||||
_traverser(infos.traverser()) {}
|
||||
TraversalExecutor::~TraversalExecutor() = default;
|
||||
|
||||
TraversalExecutor::~TraversalExecutor() {
|
||||
auto opts = _traverser.options();
|
||||
if (opts != nullptr && opts->usesPrune()) {
|
||||
auto *evaluator = opts->getPruneEvaluator();
|
||||
if (evaluator != nullptr) {
|
||||
// The InAndOutRowExpressionContext in the PruneExpressionEvaluator holds
|
||||
// an InputAqlItemRow. As the Plan holds the PruneExpressionEvaluator and
|
||||
// is destroyed after the Engine, this must be deleted by
|
||||
// unPrepareContext() - otherwise, the AqlItemBlockShell referenced by the
|
||||
// row will return its AqlItemBlock to an already destroyed
|
||||
// AqlItemBlockManager.
|
||||
evaluator->unPrepareContext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Shutdown query
|
||||
std::pair<ExecutionState, Result> TraversalExecutor::shutdown(int errorCode) {
|
||||
|
@ -163,18 +178,21 @@ std::pair<ExecutionState, TraversalStats> TraversalExecutor::produceRow(OutputAq
|
|||
} else {
|
||||
// traverser now has next v, e, p values
|
||||
if (_infos.useVertexOutput()) {
|
||||
output.cloneValueInto(_infos.vertexRegister(), _input,
|
||||
_traverser.lastVertexToAqlValue());
|
||||
AqlValue vertex = _traverser.lastVertexToAqlValue();
|
||||
AqlValueGuard guard{vertex, true};
|
||||
output.moveValueInto(_infos.vertexRegister(), _input, guard);
|
||||
}
|
||||
if (_infos.useEdgeOutput()) {
|
||||
output.cloneValueInto(_infos.edgeRegister(), _input,
|
||||
_traverser.lastEdgeToAqlValue());
|
||||
AqlValue edge = _traverser.lastEdgeToAqlValue();
|
||||
AqlValueGuard guard{edge, true};
|
||||
output.moveValueInto(_infos.edgeRegister(), _input, guard);
|
||||
}
|
||||
if (_infos.usePathOutput()) {
|
||||
transaction::BuilderLeaser tmp(_traverser.trx());
|
||||
tmp->clear();
|
||||
output.cloneValueInto(_infos.pathRegister(), _input,
|
||||
_traverser.pathToAqlValue(*tmp.builder()));
|
||||
AqlValue path = _traverser.pathToAqlValue(*tmp.builder());
|
||||
AqlValueGuard guard{path, true};
|
||||
output.moveValueInto(_infos.pathRegister(), _input, guard);
|
||||
}
|
||||
s.addFiltered(_traverser.getAndResetFilteredPaths());
|
||||
s.addScannedIndex(_traverser.getAndResetReadDocuments());
|
||||
|
|
|
@ -206,8 +206,7 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::edgeToAqlValue(size_t index) {
|
|||
return _opts->cache()->fetchEdgeAqlResult(_schreier[index]->edge);
|
||||
}
|
||||
|
||||
arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
|
||||
arangodb::velocypack::Builder& result, size_t index) {
|
||||
VPackSlice BreadthFirstEnumerator::pathToIndexToSlice(VPackBuilder& result, size_t index) {
|
||||
// TODO make deque class variable
|
||||
std::deque<size_t> fullPath;
|
||||
while (index != 0) {
|
||||
|
@ -234,7 +233,13 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
|
|||
}
|
||||
result.close(); // vertices
|
||||
result.close();
|
||||
return arangodb::aql::AqlValue(result.slice());
|
||||
TRI_ASSERT(result.isClosed());
|
||||
return result.slice();
|
||||
}
|
||||
|
||||
arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
|
||||
arangodb::velocypack::Builder& result, size_t index) {
|
||||
return arangodb::aql::AqlValue(pathToIndexToSlice(result, index));
|
||||
}
|
||||
|
||||
bool BreadthFirstEnumerator::pathContainsVertex(size_t index,
|
||||
|
@ -297,19 +302,33 @@ bool BreadthFirstEnumerator::prepareSearchOnNextDepth() {
|
|||
|
||||
bool BreadthFirstEnumerator::shouldPrune() {
|
||||
if (_opts->usesPrune()) {
|
||||
// evaluator->evaluate() might access these, so they have to live long enough.
|
||||
// To make that perfectly clear, I added a scope.
|
||||
transaction::BuilderLeaser pathBuilder(_opts->trx());
|
||||
aql::AqlValue vertex, edge;
|
||||
aql::AqlValueGuard vertexGuard{vertex, true}, edgeGuard{edge, true};
|
||||
{
|
||||
auto *evaluator = _opts->getPruneEvaluator();
|
||||
if (evaluator->needsVertex()) {
|
||||
evaluator->injectVertex(vertexToAqlValue(_schreierIndex).slice());
|
||||
// Note: vertexToAqlValue() copies the original vertex into the AqlValue.
|
||||
// This could be avoided with a function that just returns the slice,
|
||||
// as it will stay valid long enough.
|
||||
vertex = vertexToAqlValue(_schreierIndex);
|
||||
evaluator->injectVertex(vertex.slice());
|
||||
}
|
||||
if (evaluator->needsEdge()) {
|
||||
evaluator->injectEdge(edgeToAqlValue(_schreierIndex).slice());
|
||||
// Note: edgeToAqlValue() copies the original edge into the AqlValue.
|
||||
// This could be avoided with a function that just returns the slice,
|
||||
// as it will stay valid long enough.
|
||||
edge = edgeToAqlValue(_schreierIndex);
|
||||
evaluator->injectEdge(edge.slice());
|
||||
}
|
||||
transaction::BuilderLeaser builder(_opts->trx());
|
||||
if (evaluator->needsPath()) {
|
||||
aql::AqlValue val = pathToIndexToAqlValue(*builder.get(), _schreierIndex);
|
||||
evaluator->injectPath(val.slice());
|
||||
VPackSlice path = pathToIndexToSlice(*pathBuilder.get(), _schreierIndex);
|
||||
evaluator->injectPath(path);
|
||||
}
|
||||
return evaluator->evaluate();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,8 @@ class BreadthFirstEnumerator final : public arangodb::traverser::PathEnumerator
|
|||
|
||||
aql::AqlValue pathToIndexToAqlValue(arangodb::velocypack::Builder& result, size_t index);
|
||||
|
||||
velocypack::Slice pathToIndexToSlice(arangodb::velocypack::Builder& result, size_t index);
|
||||
|
||||
bool shouldPrune();
|
||||
};
|
||||
} // namespace graph
|
||||
|
|
|
@ -194,7 +194,7 @@ arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
|
|||
return _opts->cache()->fetchEdgeAqlResult(_enumeratedPath.edges.back());
|
||||
}
|
||||
|
||||
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
|
||||
VPackSlice DepthFirstEnumerator::pathToSlice(VPackBuilder& result) {
|
||||
result.clear();
|
||||
result.openObject();
|
||||
result.add(VPackValue("edges"));
|
||||
|
@ -207,29 +207,42 @@ arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypac
|
|||
result.add(VPackValue("vertices"));
|
||||
result.openArray();
|
||||
for (auto const& it : _enumeratedPath.vertices) {
|
||||
_traverser->addVertexToVelocyPack(arangodb::velocypack::StringRef(it), result);
|
||||
_traverser->addVertexToVelocyPack(VPackStringRef(it), result);
|
||||
}
|
||||
result.close();
|
||||
result.close();
|
||||
return arangodb::aql::AqlValue(result.slice());
|
||||
TRI_ASSERT(result.isClosed());
|
||||
return result.slice();
|
||||
}
|
||||
|
||||
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(VPackBuilder& result) {
|
||||
return arangodb::aql::AqlValue(pathToSlice(result));
|
||||
}
|
||||
|
||||
bool DepthFirstEnumerator::shouldPrune() {
|
||||
// We need to call prune here
|
||||
if (_opts->usesPrune()) {
|
||||
auto* evaluator = _opts->getPruneEvaluator();
|
||||
// evaluator->evaluate() might access these, so they have to live long
|
||||
// enough. To make that perfectly clear, I added a scope.
|
||||
transaction::BuilderLeaser pathBuilder(_opts->trx());
|
||||
aql::AqlValue vertex, edge;
|
||||
aql::AqlValueGuard vertexGuard{vertex, true}, edgeGuard{edge, true};
|
||||
{
|
||||
aql::PruneExpressionEvaluator* evaluator = _opts->getPruneEvaluator();
|
||||
if (evaluator->needsVertex()) {
|
||||
evaluator->injectVertex(lastVertexToAqlValue().slice());
|
||||
vertex = lastVertexToAqlValue();
|
||||
evaluator->injectVertex(vertex.slice());
|
||||
}
|
||||
if (evaluator->needsEdge()) {
|
||||
evaluator->injectEdge(lastEdgeToAqlValue().slice());
|
||||
edge = lastEdgeToAqlValue();
|
||||
evaluator->injectEdge(edge.slice());
|
||||
}
|
||||
transaction::BuilderLeaser builder(_opts->trx());
|
||||
if (evaluator->needsPath()) {
|
||||
aql::AqlValue val = pathToAqlValue(*builder.get());
|
||||
evaluator->injectPath(val.slice());
|
||||
VPackSlice path = pathToSlice(*pathBuilder.get());
|
||||
evaluator->injectPath(path);
|
||||
}
|
||||
return evaluator->evaluate();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -133,6 +133,8 @@ class DepthFirstEnumerator final : public PathEnumerator {
|
|||
|
||||
private:
|
||||
bool shouldPrune();
|
||||
|
||||
velocypack::Slice pathToSlice(arangodb::velocypack::Builder& result);
|
||||
};
|
||||
} // namespace traverser
|
||||
} // namespace arangodb
|
||||
|
|
Loading…
Reference in New Issue