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);
|
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*);
|
||||||
|
|
|
@ -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}),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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}),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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{}};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>(),
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue