create label via variable
This commit is contained in:
parent
6a4ef55e90
commit
f360555e1b
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -191,7 +191,7 @@ relationshipTypes : ':' relTypeName ( '|' ':'? relTypeName )* ;
|
||||
|
||||
nodeLabels : nodeLabel ( nodeLabel )* ;
|
||||
|
||||
nodeLabel : ':' labelName ;
|
||||
nodeLabel : ':' (labelName | expression);
|
||||
|
||||
labelName : symbolicName | parameter;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
Loading…
Reference in New Issue
Block a user