1
0
Fork 0

Aql by line mixed fixes (#8349)

This commit is contained in:
Tobias Gödderz 2019-03-14 19:38:41 +01:00 committed by Jan
parent a2ca779e71
commit 8d649903f7
26 changed files with 170 additions and 78 deletions

View File

@ -41,6 +41,7 @@ class ExecutionEngineResult {
ExecutionEngineResult(int errorNumber, std::string&& errorMessage); ExecutionEngineResult(int errorNumber, std::string&& errorMessage);
// This is not explicit on purpose // This is not explicit on purpose
// cppcheck-suppress noExplicitConstructor
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
ExecutionEngineResult(Result const& result); ExecutionEngineResult(Result const& result);
explicit ExecutionEngineResult(ExecutionEngine*); explicit ExecutionEngineResult(ExecutionEngine*);

View File

@ -40,7 +40,10 @@ using namespace arangodb::aql;
CountCollectExecutorInfos::CountCollectExecutorInfos( CountCollectExecutorInfos::CountCollectExecutorInfos(
RegisterId collectRegister, RegisterId nrInputRegisters, 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) std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(), : ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),
make_shared_unordered_set({collectRegister}), make_shared_unordered_set({collectRegister}),

View File

@ -45,8 +45,10 @@ using namespace arangodb;
using namespace arangodb::aql; using namespace arangodb::aql;
EnumerateCollectionExecutorInfos::EnumerateCollectionExecutorInfos( EnumerateCollectionExecutorInfos::EnumerateCollectionExecutorInfos(
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear, // cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine, std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
Collection const* collection, Variable const* outVariable, bool produceResult, Collection const* collection, Variable const* outVariable, bool produceResult,
std::vector<std::string> const& projections, transaction::Methods* trxPtr, std::vector<std::string> const& projections, transaction::Methods* trxPtr,

View File

@ -40,7 +40,10 @@ using namespace arangodb::aql;
EnumerateListExecutorInfos::EnumerateListExecutorInfos( EnumerateListExecutorInfos::EnumerateListExecutorInfos(
RegisterId inputRegister, RegisterId outputRegister, RegisterId nrInputRegisters, 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) std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(make_shared_unordered_set({inputRegister}), : ExecutorInfos(make_shared_unordered_set({inputRegister}),
make_shared_unordered_set({outputRegister}), make_shared_unordered_set({outputRegister}),

View File

@ -50,6 +50,7 @@ class SingleRowFetcher;
class EnumerateListExecutorInfos : public ExecutorInfos { class EnumerateListExecutorInfos : public ExecutorInfos {
public: public:
// cppcheck-suppress passedByValue
EnumerateListExecutorInfos(RegisterId inputRegister, RegisterId outputRegister, EnumerateListExecutorInfos(RegisterId inputRegister, RegisterId outputRegister,
RegisterId nrInputRegisters, RegisterId nrOutputRegisters, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
std::unordered_set<RegisterId> registersToClear, std::unordered_set<RegisterId> registersToClear,

View File

@ -24,10 +24,15 @@
using namespace arangodb::aql; 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, std::shared_ptr<std::unordered_set<RegisterId>> writeableOutputRegisters,
RegisterId nrInputRegisters, RegisterId nrOutputRegisters, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear, std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep) std::unordered_set<RegisterId> registersToKeep)
: _inRegs(std::move(readableInputRegisters)), : _inRegs(std::move(readableInputRegisters)),
_outRegs(std::move(writeableOutputRegisters)), _outRegs(std::move(writeableOutputRegisters)),

View File

@ -40,7 +40,9 @@ using namespace arangodb::aql;
FilterExecutorInfos::FilterExecutorInfos(RegisterId inputRegister, RegisterId nrInputRegisters, FilterExecutorInfos::FilterExecutorInfos(RegisterId inputRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear, std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep) std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(inputRegister), : ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(inputRegister),
nullptr, nrInputRegisters, nrOutputRegisters, nullptr, nrInputRegisters, nrOutputRegisters,

View File

@ -32,7 +32,9 @@ using namespace arangodb;
using namespace arangodb::aql; using namespace arangodb::aql;
IdExecutorInfos::IdExecutorInfos(RegisterId nrInOutRegisters, IdExecutorInfos::IdExecutorInfos(RegisterId nrInOutRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> toKeep, std::unordered_set<RegisterId> toKeep,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear) std::unordered_set<RegisterId> registersToClear)
: ExecutorInfos(make_shared_unordered_set(), make_shared_unordered_set(), : ExecutorInfos(make_shared_unordered_set(), make_shared_unordered_set(),
nrInOutRegisters, nrInOutRegisters, nrInOutRegisters, nrInOutRegisters,

View File

@ -56,6 +56,10 @@ void InAndOutRowExpressionContext::setInputRow(InputAqlItemRow input) {
_input = input; _input = input;
} }
void InAndOutRowExpressionContext::invalidateInputRow() {
_input = InputAqlItemRow{CreateInvalidInputRowHint{}};
}
AqlValue const& InAndOutRowExpressionContext::getRegisterValue(size_t i) const { AqlValue const& InAndOutRowExpressionContext::getRegisterValue(size_t i) const {
TRI_ASSERT(_input.isInitialized()); TRI_ASSERT(_input.isInitialized());
TRI_ASSERT(i < _regs.size()); TRI_ASSERT(i < _regs.size());

View File

@ -49,6 +49,8 @@ class InAndOutRowExpressionContext final : public QueryExpressionContext {
void setInputRow(InputAqlItemRow input); void setInputRow(InputAqlItemRow input);
void invalidateInputRow();
size_t numRegisters() const override { return _regs.size(); } size_t numRegisters() const override { return _regs.size(); }
AqlValue const& getRegisterValue(size_t i) const override; AqlValue const& getRegisterValue(size_t i) const override;

View File

@ -43,6 +43,7 @@
#include <lib/Logger/LogMacros.h> #include <lib/Logger/LogMacros.h>
#include <memory>
#include <utility> #include <utility>
using namespace arangodb; using namespace arangodb;
@ -65,8 +66,10 @@ static void resolveFCallConstAttributes(AstNode* fcall) {
} // namespace } // namespace
IndexExecutorInfos::IndexExecutorInfos( IndexExecutorInfos::IndexExecutorInfos(
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear, // cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine, std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
Collection const* collection, Variable const* outVariable, bool produceResult, Collection const* collection, Variable const* outVariable, bool produceResult,
std::vector<std::string> const& projections, transaction::Methods* trxPtr, std::vector<std::string> const& projections, transaction::Methods* trxPtr,
@ -80,7 +83,7 @@ IndexExecutorInfos::IndexExecutorInfos(
make_shared_unordered_set({outputRegister}), make_shared_unordered_set({outputRegister}),
nrInputRegisters, nrOutputRegisters, nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)), std::move(registersToClear), std::move(registersToKeep)),
_indexes(indexes), _indexes(std::move(indexes)),
_condition(condition), _condition(condition),
_ast(ast), _ast(ast),
_hasMultipleExpansions(false), _hasMultipleExpansions(false),
@ -107,9 +110,10 @@ IndexExecutor::IndexExecutor(Fetcher& fetcher, Infos& infos)
_allowCoveringIndexOptimization(false), _allowCoveringIndexOptimization(false),
_cursor(nullptr), _cursor(nullptr),
_cursors(_infos.getIndexes().size()), _cursors(_infos.getIndexes().size()),
_currentIndex(0),
_alreadyReturned(),
_indexesExhausted(false), _indexesExhausted(false),
_isLastIndex(false) { _isLastIndex(false) {
TRI_ASSERT(!_infos.getIndexes().empty()); TRI_ASSERT(!_infos.getIndexes().empty());
if (_infos.getCondition() != nullptr) { 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 following are needed to evaluate expressions with local data from
// the current incoming item: // the current incoming item:
auto ast = _infos.getAst(); auto ast = _infos.getAst();
AstNode* condition = const_cast<AstNode*>(_infos.getCondition()); auto* condition = const_cast<AstNode*>(_infos.getCondition());
// modify the existing node in place // modify the existing node in place
TEMPORARILY_UNLOCK_NODE(condition); TEMPORARILY_UNLOCK_NODE(condition);
@ -435,7 +439,7 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
} }
} }
TRI_ASSERT(_input.isInitialized()); TRI_ASSERT(_input.isInitialized());
TRI_ASSERT(getCursor()->hasMore()); TRI_ASSERT(getCursor() != nullptr && getCursor()->hasMore());
IndexIterator::DocumentCallback callback; IndexIterator::DocumentCallback callback;
@ -473,10 +477,8 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
TRI_ASSERT(!getIndexesExhausted()); TRI_ASSERT(!getIndexesExhausted());
// Read the next elements from the indexes // Read the next elements from the indexes
// auto saveReturned = _infos.getReturned();
bool more = readIndex(callback, hasWritten); bool more = readIndex(callback, hasWritten);
// TRI_ASSERT(!more || _infos.getCursor()->hasMore()); TRI_ASSERT(getCursor() != nullptr || !more);
TRI_ASSERT((getCursor() != nullptr || !more) || (getCursor() != nullptr && more == getCursor()->hasMore()));
if (!more) { if (!more) {
_input = InputAqlItemRow{CreateInvalidInputRowHint{}}; _input = InputAqlItemRow{CreateInvalidInputRowHint{}};

View File

@ -181,11 +181,10 @@ class IndexExecutor {
typedef std::function<void(InputAqlItemRow&, OutputAqlItemRow&, arangodb::velocypack::Slice, RegisterId)> DocumentProducingFunction; typedef std::function<void(InputAqlItemRow&, OutputAqlItemRow&, arangodb::velocypack::Slice, RegisterId)> DocumentProducingFunction;
void setProducingFunction(DocumentProducingFunction documentProducer) { void setProducingFunction(DocumentProducingFunction documentProducer) {
_documentProducer = documentProducer; _documentProducer = std::move(documentProducer);
} }
private: private:
bool initializeCursor();
bool advanceCursor(); bool advanceCursor();
void executeExpressions(InputAqlItemRow& input); void executeExpressions(InputAqlItemRow& input);
bool initIndexes(InputAqlItemRow& input); bool initIndexes(InputAqlItemRow& input);

View File

@ -58,7 +58,9 @@ class InputAqlItemRow {
explicit InputAqlItemRow(CreateInvalidInputRowHint) explicit InputAqlItemRow(CreateInvalidInputRowHint)
: _blockShell(nullptr), _baseIndex(0) {} : _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) { : _blockShell(std::move(blockShell)), _baseIndex(baseIndex) {
TRI_ASSERT(_blockShell != nullptr); TRI_ASSERT(_blockShell != nullptr);
} }

View File

@ -39,7 +39,9 @@ using namespace arangodb;
using namespace arangodb::aql; using namespace arangodb::aql;
LimitExecutorInfos::LimitExecutorInfos(RegisterId nrInputRegisters, RegisterId nrOutputRegisters, LimitExecutorInfos::LimitExecutorInfos(RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear, std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, std::unordered_set<RegisterId> registersToKeep,
size_t offset, size_t limit, bool fullCount) size_t offset, size_t limit, bool fullCount)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(), : ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),

View File

@ -25,6 +25,8 @@
#include "Aql/InAndOutRowExpressionContext.h" #include "Aql/InAndOutRowExpressionContext.h"
#include <utility>
namespace arangodb { namespace arangodb {
namespace velocypack { namespace velocypack {
class Slice; class Slice;
@ -48,7 +50,8 @@ class PruneExpressionEvaluator {
~PruneExpressionEvaluator(); ~PruneExpressionEvaluator();
bool evaluate(); 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(); } bool needsVertex() const { return _ctx.needsVertexValue(); }
void injectVertex(velocypack::Slice v) { _ctx.setVertexValue(v); } void injectVertex(velocypack::Slice v) { _ctx.setVertexValue(v); }

View File

@ -52,8 +52,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
ReturnExecutorInfos(ReturnExecutorInfos const&) = delete; ReturnExecutorInfos(ReturnExecutorInfos const&) = delete;
~ReturnExecutorInfos() = default; ~ReturnExecutorInfos() = default;
Variable const& inVariable() const { return *_inVariable; }
RegisterId getInputRegisterId() const { return _inputRegisterId; } RegisterId getInputRegisterId() const { return _inputRegisterId; }
RegisterId getOutputRegisterId() const { RegisterId getOutputRegisterId() const {
@ -68,7 +66,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
private: private:
/// @brief the variable produced by Return /// @brief the variable produced by Return
Variable const* _inVariable;
RegisterId _inputRegisterId; RegisterId _inputRegisterId;
bool _doCount; bool _doCount;
bool _returnInheritedResults; bool _returnInheritedResults;

View File

@ -35,6 +35,8 @@
#include <velocypack/StringRef.h> #include <velocypack/StringRef.h>
#include <velocypack/velocypack-aliases.h> #include <velocypack/velocypack-aliases.h>
#include <utility>
using namespace arangodb; using namespace arangodb;
using namespace arangodb::aql; using namespace arangodb::aql;
using namespace arangodb::graph; using namespace arangodb::graph;
@ -55,7 +57,8 @@ ShortestPathExecutorInfos::ShortestPathExecutorInfos(
std::unique_ptr<graph::ShortestPathFinder>&& finder, std::unique_ptr<graph::ShortestPathFinder>&& finder,
std::unordered_map<OutputName, RegisterId, OutputNameHash>&& registerMapping, std::unordered_map<OutputName, RegisterId, OutputNameHash>&& registerMapping,
InputVertex&& source, InputVertex&& target) InputVertex&& source, InputVertex&& target)
: ExecutorInfos(inputRegisters, outputRegisters, nrInputRegisters, nrOutputRegisters, : ExecutorInfos(std::move(inputRegisters), std::move(outputRegisters),
nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)), std::move(registersToClear), std::move(registersToKeep)),
_finder(std::move(finder)), _finder(std::move(finder)),
_registerMapping(std::move(registerMapping)), _registerMapping(std::move(registerMapping)),

View File

@ -58,9 +58,11 @@ class ShortestPathExecutorInfos : public ExecutorInfos {
RegisterId reg; RegisterId reg;
std::string value; std::string value;
InputVertex(std::string const value) // cppcheck-suppress passedByValue
: type(CONSTANT), reg(0), value(value) {} explicit InputVertex(std::string value)
InputVertex(RegisterId reg) : type(REGISTER), reg(reg), value("") {} : type(CONSTANT), reg(0), value(std::move(value)) {}
explicit InputVertex(RegisterId reg)
: type(REGISTER), reg(reg), value("") {}
}; };
enum OutputName { VERTEX, EDGE }; enum OutputName { VERTEX, EDGE };

View File

@ -72,21 +72,22 @@ static void parseNodeInput(AstNode const* node, std::string& id, Variable const*
} }
static ShortestPathExecutorInfos::InputVertex prepareVertexInput(ShortestPathNode const* node, static ShortestPathExecutorInfos::InputVertex prepareVertexInput(ShortestPathNode const* node,
bool isTarget) { bool isTarget) {
using InputVertex = ShortestPathExecutorInfos::InputVertex;
if (isTarget) { if (isTarget) {
if (node->usesTargetInVariable()) { if (node->usesTargetInVariable()) {
auto it = node->getRegisterPlan()->varInfo.find(node->targetInVariable()->id); auto it = node->getRegisterPlan()->varInfo.find(node->targetInVariable()->id);
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end()); TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
return {it->second.registerId}; return InputVertex{it->second.registerId};
} else { } else {
return {node->getTargetVertex()}; return InputVertex{node->getTargetVertex()};
} }
} else { } else {
if (node->usesStartInVariable()) { if (node->usesStartInVariable()) {
auto it = node->getRegisterPlan()->varInfo.find(node->startInVariable()->id); auto it = node->getRegisterPlan()->varInfo.find(node->startInVariable()->id);
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end()); TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
return {it->second.registerId}; return InputVertex{it->second.registerId};
} else { } else {
return {node->getStartVertex()}; return InputVertex{node->getStartVertex()};
} }
} }
} }

View File

@ -81,12 +81,14 @@ static std::shared_ptr<std::unordered_set<RegisterId>> mapSortRegistersToRegiste
return set; return set;
} }
SortExecutorInfos::SortExecutorInfos(std::vector<SortRegister> sortRegisters, SortExecutorInfos::SortExecutorInfos(
std::size_t limit, AqlItemBlockManager& manager, // cppcheck-suppress passedByValue
RegisterId nrInputRegisters, RegisterId nrOutputRegisters, 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> registersToClear,
std::unordered_set<RegisterId> registersToKeep, // cppcheck-suppress passedByValue
transaction::Methods* trx, bool stable) std::unordered_set<RegisterId> registersToKeep, transaction::Methods* trx, bool stable)
: ExecutorInfos(mapSortRegistersToRegisterIds(sortRegisters), nullptr, : ExecutorInfos(mapSortRegistersToRegisterIds(sortRegisters), nullptr,
nrInputRegisters, nrOutputRegisters, nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)), std::move(registersToClear), std::move(registersToKeep)),

View File

@ -116,7 +116,22 @@ TraversalExecutor::TraversalExecutor(Fetcher& fetcher, Infos& infos)
_input{CreateInvalidInputRowHint{}}, _input{CreateInvalidInputRowHint{}},
_rowState(ExecutionState::HASMORE), _rowState(ExecutionState::HASMORE),
_traverser(infos.traverser()) {} _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 // Shutdown query
std::pair<ExecutionState, Result> TraversalExecutor::shutdown(int errorCode) { std::pair<ExecutionState, Result> TraversalExecutor::shutdown(int errorCode) {
@ -163,18 +178,21 @@ std::pair<ExecutionState, TraversalStats> TraversalExecutor::produceRow(OutputAq
} else { } else {
// traverser now has next v, e, p values // traverser now has next v, e, p values
if (_infos.useVertexOutput()) { if (_infos.useVertexOutput()) {
output.cloneValueInto(_infos.vertexRegister(), _input, AqlValue vertex = _traverser.lastVertexToAqlValue();
_traverser.lastVertexToAqlValue()); AqlValueGuard guard{vertex, true};
output.moveValueInto(_infos.vertexRegister(), _input, guard);
} }
if (_infos.useEdgeOutput()) { if (_infos.useEdgeOutput()) {
output.cloneValueInto(_infos.edgeRegister(), _input, AqlValue edge = _traverser.lastEdgeToAqlValue();
_traverser.lastEdgeToAqlValue()); AqlValueGuard guard{edge, true};
output.moveValueInto(_infos.edgeRegister(), _input, guard);
} }
if (_infos.usePathOutput()) { if (_infos.usePathOutput()) {
transaction::BuilderLeaser tmp(_traverser.trx()); transaction::BuilderLeaser tmp(_traverser.trx());
tmp->clear(); tmp->clear();
output.cloneValueInto(_infos.pathRegister(), _input, AqlValue path = _traverser.pathToAqlValue(*tmp.builder());
_traverser.pathToAqlValue(*tmp.builder())); AqlValueGuard guard{path, true};
output.moveValueInto(_infos.pathRegister(), _input, guard);
} }
s.addFiltered(_traverser.getAndResetFilteredPaths()); s.addFiltered(_traverser.getAndResetFilteredPaths());
s.addScannedIndex(_traverser.getAndResetReadDocuments()); s.addScannedIndex(_traverser.getAndResetReadDocuments());

View File

@ -206,8 +206,7 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::edgeToAqlValue(size_t index) {
return _opts->cache()->fetchEdgeAqlResult(_schreier[index]->edge); return _opts->cache()->fetchEdgeAqlResult(_schreier[index]->edge);
} }
arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue( VPackSlice BreadthFirstEnumerator::pathToIndexToSlice(VPackBuilder& result, size_t index) {
arangodb::velocypack::Builder& result, size_t index) {
// TODO make deque class variable // TODO make deque class variable
std::deque<size_t> fullPath; std::deque<size_t> fullPath;
while (index != 0) { while (index != 0) {
@ -234,7 +233,13 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
} }
result.close(); // vertices result.close(); // vertices
result.close(); 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, bool BreadthFirstEnumerator::pathContainsVertex(size_t index,
@ -297,19 +302,33 @@ bool BreadthFirstEnumerator::prepareSearchOnNextDepth() {
bool BreadthFirstEnumerator::shouldPrune() { bool BreadthFirstEnumerator::shouldPrune() {
if (_opts->usesPrune()) { 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(); auto *evaluator = _opts->getPruneEvaluator();
if (evaluator->needsVertex()) { 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()) { 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()) { if (evaluator->needsPath()) {
aql::AqlValue val = pathToIndexToAqlValue(*builder.get(), _schreierIndex); VPackSlice path = pathToIndexToSlice(*pathBuilder.get(), _schreierIndex);
evaluator->injectPath(val.slice()); evaluator->injectPath(path);
} }
return evaluator->evaluate(); return evaluator->evaluate();
} }
}
return false; return false;
} }

View File

@ -186,6 +186,8 @@ class BreadthFirstEnumerator final : public arangodb::traverser::PathEnumerator
aql::AqlValue pathToIndexToAqlValue(arangodb::velocypack::Builder& result, size_t index); aql::AqlValue pathToIndexToAqlValue(arangodb::velocypack::Builder& result, size_t index);
velocypack::Slice pathToIndexToSlice(arangodb::velocypack::Builder& result, size_t index);
bool shouldPrune(); bool shouldPrune();
}; };
} // namespace graph } // namespace graph

View File

@ -194,7 +194,7 @@ arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
return _opts->cache()->fetchEdgeAqlResult(_enumeratedPath.edges.back()); return _opts->cache()->fetchEdgeAqlResult(_enumeratedPath.edges.back());
} }
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) { VPackSlice DepthFirstEnumerator::pathToSlice(VPackBuilder& result) {
result.clear(); result.clear();
result.openObject(); result.openObject();
result.add(VPackValue("edges")); result.add(VPackValue("edges"));
@ -207,29 +207,42 @@ arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypac
result.add(VPackValue("vertices")); result.add(VPackValue("vertices"));
result.openArray(); result.openArray();
for (auto const& it : _enumeratedPath.vertices) { for (auto const& it : _enumeratedPath.vertices) {
_traverser->addVertexToVelocyPack(arangodb::velocypack::StringRef(it), result); _traverser->addVertexToVelocyPack(VPackStringRef(it), result);
} }
result.close(); result.close();
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() { bool DepthFirstEnumerator::shouldPrune() {
// We need to call prune here // We need to call prune here
if (_opts->usesPrune()) { 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()) { if (evaluator->needsVertex()) {
evaluator->injectVertex(lastVertexToAqlValue().slice()); vertex = lastVertexToAqlValue();
evaluator->injectVertex(vertex.slice());
} }
if (evaluator->needsEdge()) { if (evaluator->needsEdge()) {
evaluator->injectEdge(lastEdgeToAqlValue().slice()); edge = lastEdgeToAqlValue();
evaluator->injectEdge(edge.slice());
} }
transaction::BuilderLeaser builder(_opts->trx());
if (evaluator->needsPath()) { if (evaluator->needsPath()) {
aql::AqlValue val = pathToAqlValue(*builder.get()); VPackSlice path = pathToSlice(*pathBuilder.get());
evaluator->injectPath(val.slice()); evaluator->injectPath(path);
} }
return evaluator->evaluate(); return evaluator->evaluate();
} }
}
return false; return false;
} }

View File

@ -133,6 +133,8 @@ class DepthFirstEnumerator final : public PathEnumerator {
private: private:
bool shouldPrune(); bool shouldPrune();
velocypack::Slice pathToSlice(arangodb::velocypack::Builder& result);
}; };
} // namespace traverser } // namespace traverser
} // namespace arangodb } // namespace arangodb