create label via variable

This commit is contained in:
DavIvek 2024-02-26 21:01:03 +01:00
parent 6a4ef55e90
commit f360555e1b
8 changed files with 101 additions and 42 deletions

View File

@ -1770,7 +1770,7 @@ class NodeAtom : public memgraph::query::PatternAtom {
return visitor.PostVisit(*this);
}
std::vector<memgraph::query::LabelIx> labels_;
std::vector<std::variant<memgraph::query::LabelIx, memgraph::query::Expression *>> labels_;
std::variant<std::unordered_map<memgraph::query::PropertyIx, memgraph::query::Expression *>,
memgraph::query::ParameterLookup *>
properties_;
@ -1780,7 +1780,11 @@ class NodeAtom : public memgraph::query::PatternAtom {
object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr;
object->labels_.resize(labels_.size());
for (auto i = 0; i < object->labels_.size(); ++i) {
object->labels_[i] = storage->GetLabelIx(labels_[i].name);
if (const auto *label = std::get_if<LabelIx>(&labels_[i])) {
object->labels_[i] = storage->GetLabelIx(label->name);
} else {
object->labels_[i] = std::get<Expression *>(labels_[i])->Clone(storage);
}
}
if (const auto *properties = std::get_if<std::unordered_map<PropertyIx, Expression *>>(&properties_)) {
auto &new_obj_properties = std::get<std::unordered_map<PropertyIx, Expression *>>(object->properties_);

View File

@ -1912,7 +1912,7 @@ antlrcpp::Any CypherMainVisitor::visitNodePattern(MemgraphCypher::NodePatternCon
anonymous_identifiers.push_back(&node->identifier_);
}
if (ctx->nodeLabels()) {
node->labels_ = std::any_cast<std::vector<LabelIx>>(ctx->nodeLabels()->accept(this));
node->labels_ = std::any_cast<std::vector<std::variant<LabelIx, Expression *>>>(ctx->nodeLabels()->accept(this));
}
if (ctx->properties()) {
// This can return either properties or parameters
@ -1926,16 +1926,21 @@ antlrcpp::Any CypherMainVisitor::visitNodePattern(MemgraphCypher::NodePatternCon
}
antlrcpp::Any CypherMainVisitor::visitNodeLabels(MemgraphCypher::NodeLabelsContext *ctx) {
std::vector<LabelIx> labels;
std::vector<std::variant<LabelIx, Expression *>> labels;
for (auto *node_label : ctx->nodeLabel()) {
if (node_label->labelName()->symbolicName()) {
labels.emplace_back(AddLabel(std::any_cast<std::string>(node_label->accept(this))));
if (node_label->labelName()) {
if (node_label->labelName()->symbolicName()) {
labels.emplace_back(AddLabel(std::any_cast<std::string>(node_label->accept(this))));
} else {
// If we have a parameter, we have to resolve it.
const auto *param_lookup = std::any_cast<ParameterLookup *>(node_label->accept(this));
const auto label_name = parameters_->AtTokenPosition(param_lookup->token_position_).ValueString();
labels.emplace_back(storage_->GetLabelIx(label_name));
query_info_.is_cacheable = false; // We can't cache queries with label parameters.
}
} else {
// If we have a parameter, we have to resolve it.
const auto *param_lookup = std::any_cast<ParameterLookup *>(node_label->accept(this));
const auto label_name = parameters_->AtTokenPosition(param_lookup->token_position_).ValueString();
labels.emplace_back(storage_->GetLabelIx(label_name));
query_info_.is_cacheable = false; // We can't cache queries with label parameters.
// expression
labels.emplace_back(std::any_cast<Expression *>(node_label->accept(this)));
}
}
return labels;

View File

@ -191,7 +191,7 @@ relationshipTypes : ':' relTypeName ( '|' ':'? relTypeName )* ;
nodeLabels : nodeLabel ( nodeLabel )* ;
nodeLabel : ':' labelName ;
nodeLabel : ':' (labelName | expression);
labelName : symbolicName | parameter;

View File

@ -216,8 +216,21 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, Frame *fram
auto &dba = *context.db_accessor;
auto new_node = dba.InsertVertex();
context.execution_stats[ExecutionStats::Key::CREATED_NODES] += 1;
// Evaluator should use the latest accessors, as modified in this query, when
// setting properties on new nodes.
ExpressionEvaluator evaluator(frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::NEW);
for (auto label : node_info.labels) {
auto maybe_error = new_node.AddLabel(label);
auto maybe_error = std::invoke([&] {
if (const auto *label_atom = std::get_if<storage::LabelId>(&label)) {
return new_node.AddLabel(*label_atom);
} else {
// auto key = evaluator.Visit(*std::get<Expression *>(label));
// return new_node.AddLabel(dba.NameToLabel(key.ValueString()));
auto expression = std::get<Expression *>(label);
return new_node.AddLabel(dba.NameToLabel(expression->Accept(evaluator).ValueString()));
}
});
if (maybe_error.HasError()) {
switch (maybe_error.GetError()) {
case storage::Error::SERIALIZATION_ERROR:
@ -232,10 +245,6 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, Frame *fram
}
context.execution_stats[ExecutionStats::Key::CREATED_LABELS] += 1;
}
// Evaluator should use the latest accessors, as modified in this query, when
// setting properties on new nodes.
ExpressionEvaluator evaluator(frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::NEW);
// TODO: PropsSetChecked allocates a PropertyValue, make it use context.memory
// when we update PropertyValue with custom allocator.
std::map<storage::PropertyId, storage::PropertyValue> properties;
@ -275,10 +284,22 @@ CreateNode::CreateNodeCursor::CreateNodeCursor(const CreateNode &self, utils::Me
bool CreateNode::CreateNodeCursor::Pull(Frame &frame, ExecutionContext &context) {
OOMExceptionEnabler oom_exception;
SCOPED_PROFILE_OP("CreateNode");
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::NEW);
std::vector<storage::LabelId> labels;
for (auto &label : self_.node_info_.labels) {
if (const auto *label_atom = std::get_if<storage::LabelId>(&label)) {
labels.emplace_back(*label_atom);
} else {
// auto key = evaluator.Visit(*std::get<Expression *>(label));
// labels.emplace_back(context.db_accessor->NameToLabel(key.ValueString()));
auto expression = std::get<Expression *>(label);
labels.emplace_back(context.db_accessor->NameToLabel(expression->Accept(evaluator).ValueString()));
}
}
#ifdef MG_ENTERPRISE
if (license::global_license_checker.IsEnterpriseValidFast() && context.auth_checker &&
!context.auth_checker->Has(self_.node_info_.labels,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
!context.auth_checker->Has(labels, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw QueryRuntimeException("Vertex not created due to not having enough permission!");
}
#endif
@ -368,8 +389,19 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, ExecutionContext &cont
SCOPED_PROFILE_OP_BY_REF(self_);
if (!input_cursor_->Pull(frame, context)) return false;
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::NEW);
#ifdef MG_ENTERPRISE
std::vector<storage::LabelId> labels;
for (auto label : self_.node_info_.labels) {
if (const auto *label_atom = std::get_if<storage::LabelId>(&label)) {
labels.emplace_back(*label_atom);
} else {
auto expression = std::get<Expression *>(label);
labels.emplace_back(context.db_accessor->NameToLabel(expression->Accept(evaluator).ValueString()));
}
}
if (license::global_license_checker.IsEnterpriseValidFast()) {
const auto fine_grained_permission = self_.existing_node_
? memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE
@ -379,7 +411,7 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, ExecutionContext &cont
if (context.auth_checker &&
!(context.auth_checker->Has(self_.edge_info_.edge_type,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE) &&
context.auth_checker->Has(self_.node_info_.labels, fine_grained_permission))) {
context.auth_checker->Has(labels, fine_grained_permission))) {
throw QueryRuntimeException("Edge not created due to not having enough permission!");
}
}
@ -389,12 +421,6 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, ExecutionContext &cont
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
auto &v1 = vertex_value.ValueVertex();
// Similarly to CreateNode, newly created edges and nodes should use the
// storage::View::NEW.
// E.g. we pickup new properties: `CREATE (n {p: 42}) -[:r {ep: n.p}]-> ()`
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
storage::View::NEW);
// get the destination vertex (possibly an existing node)
auto &v2 = OtherVertex(frame, context);

View File

@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// 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
@ -290,18 +290,20 @@ struct NodeCreationInfo {
NodeCreationInfo() = default;
NodeCreationInfo(Symbol symbol, std::vector<storage::LabelId> labels,
NodeCreationInfo(Symbol symbol, std::vector<std::variant<storage::LabelId, Expression *>> labels,
std::variant<PropertiesMapList, ParameterLookup *> properties)
: symbol{std::move(symbol)}, labels{std::move(labels)}, properties{std::move(properties)} {};
NodeCreationInfo(Symbol symbol, std::vector<storage::LabelId> labels, PropertiesMapList properties)
NodeCreationInfo(Symbol symbol, std::vector<std::variant<storage::LabelId, Expression *>> labels,
PropertiesMapList properties)
: symbol{std::move(symbol)}, labels{std::move(labels)}, properties{std::move(properties)} {};
NodeCreationInfo(Symbol symbol, std::vector<storage::LabelId> labels, ParameterLookup *properties)
NodeCreationInfo(Symbol symbol, std::vector<std::variant<storage::LabelId, Expression *>> labels,
ParameterLookup *properties)
: symbol{std::move(symbol)}, labels{std::move(labels)}, properties{properties} {};
Symbol symbol;
std::vector<storage::LabelId> labels;
std::vector<std::variant<storage::LabelId, Expression *>> labels;
std::variant<PropertiesMapList, ParameterLookup *> properties;
NodeCreationInfo Clone(AstStorage *storage) const {

View File

@ -358,11 +358,17 @@ void Filters::CollectPatternFilters(Pattern &pattern, SymbolTable &symbol_table,
};
auto add_node_filter = [&](NodeAtom *node) {
const auto &node_symbol = symbol_table.at(*node->identifier_);
if (!node->labels_.empty()) {
// Create a LabelsTest and store it.
auto *labels_test = storage.Create<LabelsTest>(node->identifier_, node->labels_);
std::vector<LabelIx> labels;
for (auto label : node->labels_) {
if (const auto *label_node = std::get_if<Expression *>(&label)) {
throw SemanticException("Parameter lookup not supported in MATCH/MERGE clause!");
}
labels.push_back(std::get<LabelIx>(label));
}
if (!labels.empty()) {
auto *labels_test = storage.Create<LabelsTest>(node->identifier_, labels);
auto label_filter = FilterInfo{FilterInfo::Type::Label, labels_test, std::unordered_set<Symbol>{node_symbol}};
label_filter.labels = node->labels_;
label_filter.labels = labels;
all_filters_.emplace_back(label_filter);
}
add_properties(node);

View File

@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// 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
@ -337,7 +337,15 @@ json ToJson(const std::vector<std::pair<storage::PropertyId, Expression *>> &pro
json ToJson(const NodeCreationInfo &node_info, const DbAccessor &dba) {
json self;
self["symbol"] = ToJson(node_info.symbol);
self["labels"] = ToJson(node_info.labels, dba);
std::vector<storage::LabelId> labels;
for (auto label : node_info.labels) {
if (const auto *label_node = std::get_if<Expression *>(&label)) {
labels = {};
break;
}
labels.push_back(std::get<storage::LabelId>(label));
}
self["labels"] = ToJson(labels, dba);
const auto *props = std::get_if<PropertiesMapList>(&node_info.properties);
self["properties"] = ToJson(props ? *props : PropertiesMapList{}, dba);
return self;

View File

@ -311,11 +311,19 @@ class RuleBasedPlanner {
std::unordered_set<Symbol> &bound_symbols) {
auto node_to_creation_info = [&](const NodeAtom &node) {
const auto &node_symbol = symbol_table.at(*node.identifier_);
std::vector<storage::LabelId> labels;
labels.reserve(node.labels_.size());
for (const auto &label : node.labels_) {
labels.push_back(GetLabel(label));
}
auto labels = std::invoke([&]() -> std::vector<std::variant<storage::LabelId, Expression *>> {
std::vector<std::variant<storage::LabelId, Expression *>> labels;
labels.reserve(node.labels_.size());
for (const auto &label : node.labels_) {
if (const auto *label_atom = std::get_if<LabelIx>(&label)) {
labels.emplace_back(GetLabel(*label_atom));
} else {
labels.emplace_back(std::get<Expression *>(label));
}
}
return labels;
});
auto properties = std::invoke([&]() -> std::variant<PropertiesMapList, ParameterLookup *> {
if (const auto *node_properties =