React to PR comments
This commit is contained in:
parent
5eea3ceee4
commit
cf76e0e19b
@ -200,10 +200,10 @@ class ValidFramesConsumer {
|
|||||||
explicit ValidFramesConsumer(MultiFrame &multiframe);
|
explicit ValidFramesConsumer(MultiFrame &multiframe);
|
||||||
|
|
||||||
~ValidFramesConsumer() noexcept;
|
~ValidFramesConsumer() noexcept;
|
||||||
ValidFramesConsumer(const ValidFramesConsumer &other) = default;
|
ValidFramesConsumer(const ValidFramesConsumer &other) = delete;
|
||||||
ValidFramesConsumer(ValidFramesConsumer &&other) noexcept = default;
|
ValidFramesConsumer(ValidFramesConsumer &&other) noexcept = delete;
|
||||||
ValidFramesConsumer &operator=(const ValidFramesConsumer &other) = default;
|
ValidFramesConsumer &operator=(const ValidFramesConsumer &other) = delete;
|
||||||
ValidFramesConsumer &operator=(ValidFramesConsumer &&other) noexcept = default;
|
ValidFramesConsumer &operator=(ValidFramesConsumer &&other) noexcept = delete;
|
||||||
|
|
||||||
struct Iterator {
|
struct Iterator {
|
||||||
using iterator_category = std::forward_iterator_tag;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
@ -465,194 +465,86 @@ class DistributedScanAllAndFilterCursor : public Cursor {
|
|||||||
|
|
||||||
class DistributedScanAllByPrimaryKeyCursor : public Cursor {
|
class DistributedScanAllByPrimaryKeyCursor : public Cursor {
|
||||||
public:
|
public:
|
||||||
explicit DistributedScanAllByPrimaryKeyCursor(
|
explicit DistributedScanAllByPrimaryKeyCursor(Symbol output_symbol, UniqueCursorPtr input_cursor, const char *op_name,
|
||||||
Symbol output_symbol, UniqueCursorPtr input_cursor, const char *op_name,
|
storage::v3::LabelId label,
|
||||||
std::optional<storage::v3::LabelId> label,
|
std::optional<std::vector<Expression *>> filter_expressions,
|
||||||
std::optional<std::pair<storage::v3::PropertyId, Expression *>> property_expression_pair,
|
std::vector<Expression *> primary_key)
|
||||||
std::optional<std::vector<Expression *>> filter_expressions, std::optional<std::vector<Expression *>> primary_key)
|
|
||||||
: output_symbol_(output_symbol),
|
: output_symbol_(output_symbol),
|
||||||
input_cursor_(std::move(input_cursor)),
|
input_cursor_(std::move(input_cursor)),
|
||||||
op_name_(op_name),
|
op_name_(op_name),
|
||||||
label_(label),
|
label_(label),
|
||||||
property_expression_pair_(property_expression_pair),
|
|
||||||
filter_expressions_(filter_expressions),
|
filter_expressions_(filter_expressions),
|
||||||
primary_key_(primary_key) {
|
primary_key_(primary_key) {}
|
||||||
ResetExecutionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class State : int8_t { INITIALIZING, COMPLETED };
|
enum class State : int8_t { INITIALIZING, COMPLETED };
|
||||||
|
|
||||||
using VertexAccessor = accessors::VertexAccessor;
|
using VertexAccessor = accessors::VertexAccessor;
|
||||||
|
|
||||||
bool MakeRequest(RequestRouterInterface &request_router, ExecutionContext &context) {
|
std::optional<VertexAccessor> MakeRequestSingleFrame(Frame &frame, RequestRouterInterface &request_router,
|
||||||
{
|
ExecutionContext &context) {
|
||||||
SCOPED_REQUEST_WAIT_PROFILE;
|
// Evaluate the expressions that hold the PrimaryKey.
|
||||||
std::optional<std::string> request_label;
|
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router,
|
||||||
if (label_.has_value()) {
|
storage::v3::View::NEW);
|
||||||
request_label = request_router.LabelToName(*label_);
|
|
||||||
}
|
std::vector<msgs::Value> pk;
|
||||||
current_batch_ = request_router.ScanVertices(request_label);
|
for (auto *primary_property : primary_key_) {
|
||||||
|
pk.push_back(TypedValueToValue(primary_property->Accept(evaluator)));
|
||||||
}
|
}
|
||||||
current_vertex_it_ = current_batch_.begin();
|
|
||||||
request_state_ = State::COMPLETED;
|
|
||||||
return !current_batch_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MakeRequestSingleFrame(Frame &frame, RequestRouterInterface &request_router, ExecutionContext &context) {
|
msgs::Label label = {.id = msgs::LabelId::FromUint(label_.AsUint())};
|
||||||
{
|
|
||||||
|
msgs::GetPropertiesRequest req = {.vertex_ids = {std::make_pair(label, pk)}};
|
||||||
|
auto get_prop_result = std::invoke([&context, &request_router, &req]() mutable {
|
||||||
SCOPED_REQUEST_WAIT_PROFILE;
|
SCOPED_REQUEST_WAIT_PROFILE;
|
||||||
std::optional<std::string> request_label = std::nullopt;
|
return request_router.GetProperties(req);
|
||||||
if (label_.has_value()) {
|
});
|
||||||
request_label = request_router.LabelToName(*label_);
|
MG_ASSERT(get_prop_result.size() <= 1);
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the expressions that hold the PrimaryKey.
|
if (get_prop_result.empty()) {
|
||||||
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router,
|
return std::nullopt;
|
||||||
storage::v3::View::NEW);
|
|
||||||
|
|
||||||
std::vector<msgs::Value> pk;
|
|
||||||
MG_ASSERT(primary_key_);
|
|
||||||
for (auto *primary_property : *primary_key_) {
|
|
||||||
pk.push_back(TypedValueToValue(primary_key->Accept(evaluator)));
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs::Label label = {.id = msgs::LabelId::FromUint(label_->AsUint())};
|
|
||||||
|
|
||||||
msgs::GetPropertiesRequest req = {.vertex_ids = {std::make_pair(label, pk)}};
|
|
||||||
auto get_prop_result = request_router.GetProperties(req);
|
|
||||||
MG_ASSERT(get_prop_result.size() <= 1);
|
|
||||||
|
|
||||||
if (get_prop_result.empty()) {
|
|
||||||
current_batch_ = std::vector<VertexAccessor>{};
|
|
||||||
} else {
|
|
||||||
auto properties = get_prop_result[0].props;
|
|
||||||
// TODO (gvolfing) figure out labels when relevant.
|
|
||||||
msgs::Vertex vertex = {.id = get_prop_result[0].vertex, .labels = {}};
|
|
||||||
|
|
||||||
current_batch_ = {VertexAccessor(vertex, properties, &request_router)};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
current_vertex_it_ = current_batch_.begin();
|
auto properties = get_prop_result[0].props;
|
||||||
request_state_ = State::COMPLETED;
|
// TODO (gvolfing) figure out labels when relevant.
|
||||||
return !current_batch_.empty();
|
msgs::Vertex vertex = {.id = get_prop_result[0].vertex, .labels = {}};
|
||||||
|
|
||||||
|
return VertexAccessor(vertex, properties, &request_router);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pull(Frame &frame, ExecutionContext &context) override {
|
bool Pull(Frame &frame, ExecutionContext &context) override {
|
||||||
SCOPED_PROFILE_OP(op_name_);
|
SCOPED_PROFILE_OP(op_name_);
|
||||||
|
|
||||||
|
if (MustAbort(context)) {
|
||||||
|
throw HintedAbortError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input_cursor_->Pull(frame, context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto &request_router = *context.request_router;
|
auto &request_router = *context.request_router;
|
||||||
while (true) {
|
auto vertex = MakeRequestSingleFrame(frame, request_router, context);
|
||||||
if (MustAbort(context)) {
|
if (vertex) {
|
||||||
throw HintedAbortError();
|
frame[output_symbol_] = TypedValue(std::move(*vertex));
|
||||||
}
|
|
||||||
|
|
||||||
if (request_state_ == State::INITIALIZING) {
|
|
||||||
if (!input_cursor_->Pull(frame, context)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_vertex_it_ == current_batch_.end() &&
|
|
||||||
(request_state_ == State::COMPLETED || !MakeRequestSingleFrame(frame, request_router, context))) {
|
|
||||||
ResetExecutionState();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame[output_symbol_] = TypedValue(std::move(*current_vertex_it_));
|
|
||||||
++current_vertex_it_;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
|
||||||
void PrepareNextFrames(ExecutionContext &context) {
|
|
||||||
auto &request_router = *context.request_router;
|
|
||||||
|
|
||||||
input_cursor_->PullMultiple(*own_multi_frames_, context);
|
|
||||||
valid_frames_consumer_ = own_multi_frames_->GetValidFramesConsumer();
|
|
||||||
valid_frames_it_ = valid_frames_consumer_->begin();
|
|
||||||
|
|
||||||
MakeRequest(request_router, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool HasNextFrame() {
|
|
||||||
return current_vertex_it_ != current_batch_.end() && valid_frames_it_ != valid_frames_consumer_->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameWithValidity GetNextFrame(ExecutionContext &context) {
|
|
||||||
MG_ASSERT(HasNextFrame());
|
|
||||||
|
|
||||||
auto frame = *valid_frames_it_;
|
|
||||||
frame[output_symbol_] = TypedValue(*current_vertex_it_);
|
|
||||||
|
|
||||||
++current_vertex_it_;
|
|
||||||
if (current_vertex_it_ == current_batch_.end()) {
|
|
||||||
valid_frames_it_->MakeInvalid();
|
|
||||||
++valid_frames_it_;
|
|
||||||
|
|
||||||
if (valid_frames_it_ == valid_frames_consumer_->end()) {
|
|
||||||
PrepareNextFrames(context);
|
|
||||||
} else {
|
|
||||||
current_vertex_it_ = current_batch_.begin();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PullMultiple(MultiFrame &input_multi_frame, ExecutionContext &context) override {
|
void PullMultiple(MultiFrame &input_multi_frame, ExecutionContext &context) override {
|
||||||
SCOPED_PROFILE_OP(op_name_);
|
throw utils::NotYetImplemented("Multiframe version of ScanAllByPrimaryKey is yet to be implemented.");
|
||||||
|
|
||||||
if (!own_multi_frames_.has_value()) {
|
|
||||||
own_multi_frames_.emplace(MultiFrame(input_multi_frame.GetFirstFrame().elems().size(),
|
|
||||||
kNumberOfFramesInMultiframe, input_multi_frame.GetMemoryResource()));
|
|
||||||
PrepareNextFrames(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (MustAbort(context)) {
|
|
||||||
throw HintedAbortError();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto invalid_frames_populator = input_multi_frame.GetInvalidFramesPopulator();
|
|
||||||
auto invalid_frame_it = invalid_frames_populator.begin();
|
|
||||||
auto has_modified_at_least_one_frame = false;
|
|
||||||
|
|
||||||
while (invalid_frames_populator.end() != invalid_frame_it && HasNextFrame()) {
|
|
||||||
has_modified_at_least_one_frame = true;
|
|
||||||
*invalid_frame_it = GetNextFrame(context);
|
|
||||||
++invalid_frame_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_modified_at_least_one_frame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Reset() override { input_cursor_->Reset(); }
|
||||||
|
|
||||||
void Shutdown() override { input_cursor_->Shutdown(); }
|
void Shutdown() override { input_cursor_->Shutdown(); }
|
||||||
|
|
||||||
void ResetExecutionState() {
|
|
||||||
current_batch_.clear();
|
|
||||||
current_vertex_it_ = current_batch_.end();
|
|
||||||
request_state_ = State::INITIALIZING;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() override {
|
|
||||||
input_cursor_->Reset();
|
|
||||||
ResetExecutionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Symbol output_symbol_;
|
const Symbol output_symbol_;
|
||||||
const UniqueCursorPtr input_cursor_;
|
const UniqueCursorPtr input_cursor_;
|
||||||
const char *op_name_;
|
const char *op_name_;
|
||||||
std::vector<VertexAccessor> current_batch_;
|
storage::v3::LabelId label_;
|
||||||
std::vector<VertexAccessor>::iterator current_vertex_it_;
|
|
||||||
State request_state_ = State::INITIALIZING;
|
|
||||||
std::optional<storage::v3::LabelId> label_;
|
|
||||||
std::optional<std::pair<storage::v3::PropertyId, Expression *>> property_expression_pair_;
|
|
||||||
std::optional<std::vector<Expression *>> filter_expressions_;
|
std::optional<std::vector<Expression *>> filter_expressions_;
|
||||||
std::optional<std::vector<Expression *>> primary_key_;
|
std::vector<Expression *> primary_key_;
|
||||||
std::optional<MultiFrame> own_multi_frames_;
|
std::optional<MultiFrame> own_multi_frames_;
|
||||||
std::optional<ValidFramesConsumer> valid_frames_consumer_;
|
std::optional<ValidFramesConsumer> valid_frames_consumer_;
|
||||||
ValidFramesConsumer::Iterator valid_frames_it_;
|
ValidFramesConsumer::Iterator valid_frames_it_;
|
||||||
@ -767,9 +659,9 @@ ACCEPT_WITH_INPUT(ScanAllByPrimaryKey)
|
|||||||
UniqueCursorPtr ScanAllByPrimaryKey::MakeCursor(utils::MemoryResource *mem) const {
|
UniqueCursorPtr ScanAllByPrimaryKey::MakeCursor(utils::MemoryResource *mem) const {
|
||||||
EventCounter::IncrementCounter(EventCounter::ScanAllByPrimaryKeyOperator);
|
EventCounter::IncrementCounter(EventCounter::ScanAllByPrimaryKeyOperator);
|
||||||
|
|
||||||
return MakeUniqueCursorPtr<DistributedScanAllByPrimaryKeyCursor>(
|
return MakeUniqueCursorPtr<DistributedScanAllByPrimaryKeyCursor>(mem, output_symbol_, input_->MakeCursor(mem),
|
||||||
mem, output_symbol_, input_->MakeCursor(mem), "ScanAllByPrimaryKey", label_,
|
"ScanAllByPrimaryKey", label_,
|
||||||
std::nullopt /*property_expression_pair*/, std::nullopt /*filter_expressions*/, primary_key_);
|
std::nullopt /*filter_expressions*/, primary_key_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expand::Expand(const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, Symbol node_symbol,
|
Expand::Expand(const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, Symbol node_symbol,
|
||||||
|
@ -67,7 +67,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor {
|
|||||||
bool PreVisit(ScanAllByLabelPropertyValue &) override;
|
bool PreVisit(ScanAllByLabelPropertyValue &) override;
|
||||||
bool PreVisit(ScanAllByLabelPropertyRange &) override;
|
bool PreVisit(ScanAllByLabelPropertyRange &) override;
|
||||||
bool PreVisit(ScanAllByLabelProperty &) override;
|
bool PreVisit(ScanAllByLabelProperty &) override;
|
||||||
bool PreVisit(ScanAllByPrimaryKey & /*unused*/) override;
|
bool PreVisit(ScanAllByPrimaryKey &) override;
|
||||||
|
|
||||||
bool PreVisit(Expand &) override;
|
bool PreVisit(Expand &) override;
|
||||||
bool PreVisit(ExpandVariable &) override;
|
bool PreVisit(ExpandVariable &) override;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@ -35,6 +35,7 @@ PRE_VISIT(ScanAllByLabel, RWType::R, true)
|
|||||||
PRE_VISIT(ScanAllByLabelPropertyRange, RWType::R, true)
|
PRE_VISIT(ScanAllByLabelPropertyRange, RWType::R, true)
|
||||||
PRE_VISIT(ScanAllByLabelPropertyValue, RWType::R, true)
|
PRE_VISIT(ScanAllByLabelPropertyValue, RWType::R, true)
|
||||||
PRE_VISIT(ScanAllByLabelProperty, RWType::R, true)
|
PRE_VISIT(ScanAllByLabelProperty, RWType::R, true)
|
||||||
|
PRE_VISIT(ScanAllByPrimaryKey, RWType::R, true)
|
||||||
|
|
||||||
PRE_VISIT(Expand, RWType::R, true)
|
PRE_VISIT(Expand, RWType::R, true)
|
||||||
PRE_VISIT(ExpandVariable, RWType::R, true)
|
PRE_VISIT(ExpandVariable, RWType::R, true)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@ -59,6 +59,7 @@ class ReadWriteTypeChecker : public virtual HierarchicalLogicalOperatorVisitor {
|
|||||||
bool PreVisit(ScanAllByLabelPropertyValue &) override;
|
bool PreVisit(ScanAllByLabelPropertyValue &) override;
|
||||||
bool PreVisit(ScanAllByLabelPropertyRange &) override;
|
bool PreVisit(ScanAllByLabelPropertyRange &) override;
|
||||||
bool PreVisit(ScanAllByLabelProperty &) override;
|
bool PreVisit(ScanAllByLabelProperty &) override;
|
||||||
|
bool PreVisit(ScanAllByPrimaryKey &) override;
|
||||||
|
|
||||||
bool PreVisit(Expand &) override;
|
bool PreVisit(Expand &) override;
|
||||||
bool PreVisit(ExpandVariable &) override;
|
bool PreVisit(ExpandVariable &) override;
|
||||||
|
@ -569,8 +569,8 @@ class IndexLookupRewriter final : public HierarchicalLogicalOperatorVisitor {
|
|||||||
const auto &modified_symbols = scan.ModifiedSymbols(*symbol_table_);
|
const auto &modified_symbols = scan.ModifiedSymbols(*symbol_table_);
|
||||||
std::unordered_set<Symbol> bound_symbols(modified_symbols.begin(), modified_symbols.end());
|
std::unordered_set<Symbol> bound_symbols(modified_symbols.begin(), modified_symbols.end());
|
||||||
|
|
||||||
// Try to see if we can use label+property index. If not, try to use
|
// Try to see if we can use label + primary-key or label + property index.
|
||||||
// just the label index.
|
// If not, try to use just the label index.
|
||||||
const auto labels = filters_.FilteredLabels(node_symbol);
|
const auto labels = filters_.FilteredLabels(node_symbol);
|
||||||
if (labels.empty()) {
|
if (labels.empty()) {
|
||||||
// Without labels, we cannot generate any indexed ScanAll.
|
// Without labels, we cannot generate any indexed ScanAll.
|
||||||
@ -583,19 +583,57 @@ class IndexLookupRewriter final : public HierarchicalLogicalOperatorVisitor {
|
|||||||
query::v2::LabelIx prim_label;
|
query::v2::LabelIx prim_label;
|
||||||
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> primary_key;
|
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> primary_key;
|
||||||
|
|
||||||
|
auto extract_primary_key = [this](storage::v3::LabelId label,
|
||||||
|
std::vector<query::v2::plan::FilterInfo> property_filters)
|
||||||
|
-> std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> {
|
||||||
|
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> pk_temp;
|
||||||
|
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> pk;
|
||||||
|
std::vector<memgraph::storage::v3::SchemaProperty> schema = db_->GetSchemaForLabel(label);
|
||||||
|
|
||||||
|
std::vector<storage::v3::PropertyId> schema_properties;
|
||||||
|
schema_properties.reserve(schema.size());
|
||||||
|
|
||||||
|
std::transform(schema.begin(), schema.end(), std::back_inserter(schema_properties),
|
||||||
|
[](const auto &schema_elem) { return schema_elem.property_id; });
|
||||||
|
|
||||||
|
for (const auto &property_filter : property_filters) {
|
||||||
|
const auto &property_id = db_->NameToProperty(property_filter.property_filter->property_.name);
|
||||||
|
if (std::find(schema_properties.begin(), schema_properties.end(), property_id) != schema_properties.end()) {
|
||||||
|
pk_temp.emplace_back(std::make_pair(property_filter.expression, property_filter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure pk is in the same order as schema_properties.
|
||||||
|
for (const auto &schema_prop : schema_properties) {
|
||||||
|
for (auto &pk_temp_prop : pk_temp) {
|
||||||
|
const auto &property_id = db_->NameToProperty(pk_temp_prop.second.property_filter->property_.name);
|
||||||
|
if (schema_prop == property_id) {
|
||||||
|
pk.push_back(pk_temp_prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MG_ASSERT(pk.size() == pk_temp.size(),
|
||||||
|
"The two vectors should represent the same primary key with a possibly different order of contained "
|
||||||
|
"elements.");
|
||||||
|
|
||||||
|
return pk.size() == schema_properties.size()
|
||||||
|
? pk
|
||||||
|
: std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>>{};
|
||||||
|
};
|
||||||
|
|
||||||
if (!property_filters.empty()) {
|
if (!property_filters.empty()) {
|
||||||
for (const auto &label : labels) {
|
for (const auto &label : labels) {
|
||||||
if (db_->LabelIndexExists(GetLabel(label))) {
|
if (db_->PrimaryLabelExists(GetLabel(label))) {
|
||||||
prim_label = label;
|
prim_label = label;
|
||||||
primary_key = db_->ExtractPrimaryKey(GetLabel(prim_label), property_filters);
|
primary_key = extract_primary_key(GetLabel(prim_label), property_filters);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!primary_key.empty()) {
|
if (!primary_key.empty()) {
|
||||||
// Mark the expressions so they won't be used for an additional, unnecessary filter.
|
// Mark the expressions so they won't be used for an additional, unnecessary filter.
|
||||||
for (const auto &primary_property : primary_key) {
|
for (const auto &primary_property : primary_key) {
|
||||||
filter_exprs_for_removal_.insert(pk.first);
|
filter_exprs_for_removal_.insert(primary_property.first);
|
||||||
filters_.EraseFilter(pk.second);
|
filters_.EraseFilter(primary_property.second);
|
||||||
}
|
}
|
||||||
EraseLabelFilters(node_symbol, prim_label);
|
EraseLabelFilters(node_symbol, prim_label);
|
||||||
std::vector<query::v2::Expression *> pk_expressions;
|
std::vector<query::v2::Expression *> pk_expressions;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2022 Memgraph Ltd.
|
// Copyright 2023 Memgraph Ltd.
|
||||||
//
|
//
|
||||||
// Use of this software is governed by the Business Source License
|
// Use of this software is governed by the Business Source License
|
||||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "utils/bound.hpp"
|
#include "utils/bound.hpp"
|
||||||
|
#include "utils/exceptions.hpp"
|
||||||
#include "utils/fnv.hpp"
|
#include "utils/fnv.hpp"
|
||||||
|
|
||||||
namespace memgraph::query::v2::plan {
|
namespace memgraph::query::v2::plan {
|
||||||
@ -54,31 +55,16 @@ class VertexCountCache {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LabelIndexExists(storage::v3::LabelId label) { return request_router_->IsPrimaryLabel(label); }
|
bool LabelIndexExists(storage::v3::LabelId label) {
|
||||||
|
throw utils::NotYetImplemented("Label indicies are yet to be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PrimaryLabelExists(storage::v3::LabelId label) { return request_router_->IsPrimaryLabel(label); }
|
||||||
|
|
||||||
bool LabelPropertyIndexExists(storage::v3::LabelId /*label*/, storage::v3::PropertyId /*property*/) { return false; }
|
bool LabelPropertyIndexExists(storage::v3::LabelId /*label*/, storage::v3::PropertyId /*property*/) { return false; }
|
||||||
|
|
||||||
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> ExtractPrimaryKey(
|
std::vector<memgraph::storage::v3::SchemaProperty> GetSchemaForLabel(storage::v3::LabelId label) {
|
||||||
storage::v3::LabelId label, std::vector<query::v2::plan::FilterInfo> property_filters) {
|
return request_router_->GetSchemaForLabel(label);
|
||||||
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> pk;
|
|
||||||
const auto schema = request_router_->GetSchemaForLabel(label);
|
|
||||||
|
|
||||||
std::vector<storage::v3::PropertyId> schema_properties;
|
|
||||||
schema_properties.reserve(schema.size());
|
|
||||||
|
|
||||||
std::transform(schema.begin(), schema.end(), std::back_inserter(schema_properties),
|
|
||||||
[](const auto &schema_elem) { return schema_elem.property_id; });
|
|
||||||
|
|
||||||
for (const auto &property_filter : property_filters) {
|
|
||||||
const auto &property_id = NameToProperty(property_filter.property_filter->property_.name);
|
|
||||||
if (std::find(schema_properties.begin(), schema_properties.end(), property_id) != schema_properties.end()) {
|
|
||||||
pk.emplace_back(std::make_pair(property_filter.expression, property_filter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pk.size() == schema_properties.size()
|
|
||||||
? pk
|
|
||||||
: std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>>{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestRouterInterface *request_router_;
|
RequestRouterInterface *request_router_;
|
||||||
|
@ -539,12 +539,12 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::GetPropertiesRequest &&req) {
|
|||||||
const VertexAccessor &v_acc,
|
const VertexAccessor &v_acc,
|
||||||
const std::optional<EdgeAccessor> &e_acc) -> ShardResult<std::map<PropertyId, Value>> {
|
const std::optional<EdgeAccessor> &e_acc) -> ShardResult<std::map<PropertyId, Value>> {
|
||||||
if (!req.property_ids) {
|
if (!req.property_ids) {
|
||||||
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
|
||||||
MG_ASSERT(schema);
|
|
||||||
|
|
||||||
if (e_acc) {
|
if (e_acc) {
|
||||||
return CollectAllPropertiesFromAccessor(*e_acc, view);
|
return CollectAllPropertiesFromAccessor(*e_acc, view);
|
||||||
}
|
}
|
||||||
|
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
||||||
|
MG_ASSERT(schema);
|
||||||
|
|
||||||
return CollectAllPropertiesFromAccessor(v_acc, view, *schema);
|
return CollectAllPropertiesFromAccessor(v_acc, view, *schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +486,6 @@ auto GetForeach(AstStorage &storage, NamedExpression *named_expr, const std::vec
|
|||||||
#define EDGE(...) memgraph::query::test_common::GetEdge(storage, __VA_ARGS__)
|
#define EDGE(...) memgraph::query::test_common::GetEdge(storage, __VA_ARGS__)
|
||||||
#define EDGE_VARIABLE(...) memgraph::query::test_common::GetEdgeVariable(storage, __VA_ARGS__)
|
#define EDGE_VARIABLE(...) memgraph::query::test_common::GetEdgeVariable(storage, __VA_ARGS__)
|
||||||
#define PATTERN(...) memgraph::query::test_common::GetPattern(storage, {__VA_ARGS__})
|
#define PATTERN(...) memgraph::query::test_common::GetPattern(storage, {__VA_ARGS__})
|
||||||
#define PATTERN(...) memgraph::query::test_common::GetPattern(storage, {__VA_ARGS__})
|
|
||||||
#define NAMED_PATTERN(name, ...) memgraph::query::test_common::GetPattern(storage, name, {__VA_ARGS__})
|
#define NAMED_PATTERN(name, ...) memgraph::query::test_common::GetPattern(storage, name, {__VA_ARGS__})
|
||||||
#define OPTIONAL_MATCH(...) \
|
#define OPTIONAL_MATCH(...) \
|
||||||
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::Match>(true), {__VA_ARGS__})
|
memgraph::query::test_common::GetWithPatterns(storage.Create<memgraph::query::Match>(true), {__VA_ARGS__})
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "query/v2/plan/operator.hpp"
|
#include "query/v2/plan/operator.hpp"
|
||||||
#include "query/v2/plan/planner.hpp"
|
#include "query/v2/plan/planner.hpp"
|
||||||
#include "query/v2/plan/preprocess.hpp"
|
#include "query/v2/plan/preprocess.hpp"
|
||||||
|
#include "utils/exceptions.hpp"
|
||||||
|
|
||||||
namespace memgraph::query::v2::plan {
|
namespace memgraph::query::v2::plan {
|
||||||
|
|
||||||
@ -289,7 +290,7 @@ class FakeDistributedDbAccessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool LabelIndexExists(memgraph::storage::v3::LabelId label) const {
|
bool LabelIndexExists(memgraph::storage::v3::LabelId label) const {
|
||||||
return label_index_.find(label) != label_index_.end();
|
throw utils::NotYetImplemented("Label indicies are yet to be implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LabelPropertyIndexExists(memgraph::storage::v3::LabelId label,
|
bool LabelPropertyIndexExists(memgraph::storage::v3::LabelId label,
|
||||||
@ -302,6 +303,8 @@ class FakeDistributedDbAccessor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PrimaryLabelExists(storage::v3::LabelId label) { return label_index_.find(label) != label_index_.end(); }
|
||||||
|
|
||||||
void SetIndexCount(memgraph::storage::v3::LabelId label, int64_t count) { label_index_[label] = count; }
|
void SetIndexCount(memgraph::storage::v3::LabelId label, int64_t count) { label_index_[label] = count; }
|
||||||
|
|
||||||
void SetIndexCount(memgraph::storage::v3::LabelId label, memgraph::storage::v3::PropertyId property, int64_t count) {
|
void SetIndexCount(memgraph::storage::v3::LabelId label, memgraph::storage::v3::PropertyId property, int64_t count) {
|
||||||
@ -382,13 +385,27 @@ class FakeDistributedDbAccessor {
|
|||||||
return memgraph::storage::v3::PropertyId::FromUint(0);
|
return memgraph::storage::v3::PropertyId::FromUint(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<memgraph::storage::v3::SchemaProperty> GetSchemaForLabel(storage::v3::LabelId label) {
|
||||||
|
auto schema_properties = schemas_.at(label);
|
||||||
|
std::vector<memgraph::storage::v3::SchemaProperty> ret;
|
||||||
|
std::transform(schema_properties.begin(), schema_properties.end(), std::back_inserter(ret), [](const auto &prop) {
|
||||||
|
memgraph::storage::v3::SchemaProperty schema_prop = {
|
||||||
|
.property_id = prop,
|
||||||
|
// This should not be hardcoded, but for testing purposes it will suffice.
|
||||||
|
.type = memgraph::common::SchemaType::INT};
|
||||||
|
|
||||||
|
return schema_prop;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> ExtractPrimaryKey(
|
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> ExtractPrimaryKey(
|
||||||
storage::v3::LabelId label, std::vector<query::v2::plan::FilterInfo> property_filters) {
|
storage::v3::LabelId label, std::vector<query::v2::plan::FilterInfo> property_filters) {
|
||||||
MG_ASSERT(schemas_.contains(label),
|
MG_ASSERT(schemas_.contains(label),
|
||||||
"You did not specify the Schema for this label! Use FakeDistributedDbAccessor::CreateSchema(...).");
|
"You did not specify the Schema for this label! Use FakeDistributedDbAccessor::CreateSchema(...).");
|
||||||
|
|
||||||
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> pk;
|
std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>> pk;
|
||||||
const auto schema = GetSchemaForLabel(label);
|
const auto schema = GetSchemaPropertiesForLabel(label);
|
||||||
|
|
||||||
std::vector<storage::v3::PropertyId> schema_properties;
|
std::vector<storage::v3::PropertyId> schema_properties;
|
||||||
schema_properties.reserve(schema.size());
|
schema_properties.reserve(schema.size());
|
||||||
@ -408,7 +425,7 @@ class FakeDistributedDbAccessor {
|
|||||||
: std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>>{};
|
: std::vector<std::pair<query::v2::Expression *, query::v2::plan::FilterInfo>>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<memgraph::storage::v3::PropertyId> GetSchemaForLabel(storage::v3::LabelId label) {
|
std::vector<memgraph::storage::v3::PropertyId> GetSchemaPropertiesForLabel(storage::v3::LabelId label) {
|
||||||
return schemas_.at(label);
|
return schemas_.at(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user