From f73bb9d3f07e42a71406fbac5db4f999a24bd507 Mon Sep 17 00:00:00 2001 From: andyfeng Date: Fri, 23 Dec 2022 19:22:32 +0800 Subject: [PATCH] add set rel property planning (#1136) --- src/binder/bind/bind_ddl.cpp | 1 + src/binder/bind/bind_updating_clause.cpp | 68 +++++++--- src/binder/query/CMakeLists.txt | 1 + src/binder/query/bound_set_clause.cpp | 33 +++++ src/include/binder/binder.h | 9 +- .../query/updating_clause/bound_set_clause.h | 71 ++++++++--- .../parser/query/updating_clause/set_clause.h | 21 ++-- src/include/parser/transformer.h | 3 +- .../logical_operator/base_logical_operator.h | 1 + .../logical_operator/logical_create.h | 25 ++-- .../logical_operator/logical_delete.h | 25 ++-- .../logical_operator/logical_set.h | 46 +++++-- ...gical_create_delete.h => logical_update.h} | 28 ++--- src/include/planner/update_planner.h | 12 +- src/include/processor/mapper/plan_mapper.h | 5 +- .../processor/operator/physical_operator.h | 3 +- src/include/processor/operator/update/set.h | 81 +++++++++--- src/parser/transformer.cpp | 5 +- .../operator/base_logical_operator.cpp | 3 + src/planner/operator/logical_create.cpp | 4 +- src/planner/update_planner.cpp | 119 +++++++++++------- src/processor/mapper/map_create.cpp | 4 +- src/processor/mapper/map_delete.cpp | 4 +- src/processor/mapper/map_set.cpp | 59 ++++++--- src/processor/mapper/plan_mapper.cpp | 5 +- src/processor/operator/physical_operator.cpp | 11 +- src/processor/operator/update/set.cpp | 61 ++++++--- test/runner/e2e_exception_test.cpp | 5 +- 28 files changed, 493 insertions(+), 220 deletions(-) create mode 100644 src/binder/query/bound_set_clause.cpp rename src/include/planner/logical_plan/logical_operator/{logical_create_delete.h => logical_update.h} (56%) diff --git a/src/binder/bind/bind_ddl.cpp b/src/binder/bind/bind_ddl.cpp index 7109ddecd8..b6154144c8 100644 --- a/src/binder/bind/bind_ddl.cpp +++ b/src/binder/bind/bind_ddl.cpp @@ -3,6 +3,7 @@ #include "binder/bind/bound_drop_table.h" #include "binder/binder.h" #include "parser/ddl/create_node_clause.h" +#include "parser/ddl/create_rel_clause.h" #include "parser/ddl/drop_table.h" namespace kuzu { diff --git a/src/binder/bind/bind_updating_clause.cpp b/src/binder/bind/bind_updating_clause.cpp index 8274d53d2a..ff0b571c45 100644 --- a/src/binder/bind/bind_updating_clause.cpp +++ b/src/binder/bind/bind_updating_clause.cpp @@ -108,38 +108,66 @@ unique_ptr Binder::bindSetClause(const UpdatingClause& upda auto boundSetClause = make_unique(); for (auto i = 0u; i < setClause.getNumSetItems(); ++i) { auto setItem = setClause.getSetItem(i); - auto boundLhs = expressionBinder.bindExpression(*setItem->origin); - auto boundNodeOrRel = boundLhs->getChild(0); - if (boundNodeOrRel->dataType.typeID != NODE) { - throw BinderException("Set " + Types::dataTypeToString(boundNodeOrRel->dataType) + + auto nodeOrRel = expressionBinder.bindExpression(*setItem.first->getChild(0)); + switch (nodeOrRel->dataType.typeID) { + case DataTypeID::NODE: { + auto node = static_pointer_cast(nodeOrRel); + boundSetClause->addSetNodeProperty(bindSetNodeProperty(node, setItem)); + } break; + case DataTypeID::REL: { + auto rel = static_pointer_cast(nodeOrRel); + boundSetClause->addSetRelProperty(bindSetRelProperty(rel, setItem)); + } break; + default: + throw BinderException("Set " + expressionTypeToString(nodeOrRel->expressionType) + " property is supported."); } - auto boundNode = static_pointer_cast(boundNodeOrRel); - if (boundNode->isMultiLabeled()) { - throw BinderException("Set property of node " + boundNode->getRawName() + - " with multiple node labels is not supported."); - } - auto boundRhs = expressionBinder.bindExpression(*setItem->target); - boundRhs = ExpressionBinder::implicitCastIfNecessary(boundRhs, boundLhs->dataType); - boundSetClause->addSetItem(make_pair(boundLhs, boundRhs)); } return boundSetClause; } +unique_ptr Binder::bindSetNodeProperty( + shared_ptr node, pair setItem) { + if (node->isMultiLabeled()) { + throw BinderException("Set property of node " + node->getRawName() + + " with multiple node labels is not supported."); + } + return make_unique(std::move(node), bindSetItem(setItem)); +} + +unique_ptr Binder::bindSetRelProperty( + shared_ptr rel, pair setItem) { + if (rel->isMultiLabeled() || rel->isBoundByMultiLabeledNode()) { + throw BinderException("Set property of rel " + rel->getRawName() + + " with multiple rel labels or bound by multiple node labels " + "is not supported."); + } + return make_unique(std::move(rel), bindSetItem(setItem)); +} + +expression_pair Binder::bindSetItem(pair setItem) { + auto boundLhs = expressionBinder.bindExpression(*setItem.first); + auto boundRhs = expressionBinder.bindExpression(*setItem.second); + boundRhs = ExpressionBinder::implicitCastIfNecessary(boundRhs, boundLhs->dataType); + return make_pair(std::move(boundLhs), std::move(boundRhs)); +} + unique_ptr Binder::bindDeleteClause(const UpdatingClause& updatingClause) { auto& deleteClause = (DeleteClause&)updatingClause; auto boundDeleteClause = make_unique(); for (auto i = 0u; i < deleteClause.getNumExpressions(); ++i) { - auto boundExpression = expressionBinder.bindExpression(*deleteClause.getExpression(i)); - if (boundExpression->dataType.typeID == NODE) { - auto deleteNode = bindDeleteNode(static_pointer_cast(boundExpression)); + auto nodeOrRel = expressionBinder.bindExpression(*deleteClause.getExpression(i)); + switch (nodeOrRel->dataType.typeID) { + case DataTypeID::NODE: { + auto deleteNode = bindDeleteNode(static_pointer_cast(nodeOrRel)); boundDeleteClause->addDeleteNode(std::move(deleteNode)); - } else if (boundExpression->dataType.typeID == REL) { - auto deleteRel = bindDeleteRel(static_pointer_cast(boundExpression)); + } break; + case DataTypeID::REL: { + auto deleteRel = bindDeleteRel(static_pointer_cast(nodeOrRel)); boundDeleteClause->addDeleteRel(std::move(deleteRel)); - } else { - throw BinderException("Delete " + - expressionTypeToString(boundExpression->expressionType) + + } break; + default: + throw BinderException("Delete " + expressionTypeToString(nodeOrRel->expressionType) + " is not supported."); } } diff --git a/src/binder/query/CMakeLists.txt b/src/binder/query/CMakeLists.txt index 30d0752d5f..f7319530b4 100644 --- a/src/binder/query/CMakeLists.txt +++ b/src/binder/query/CMakeLists.txt @@ -4,6 +4,7 @@ add_library( bound_create_clause.cpp bound_delete_clause.cpp bound_projection_body.cpp + bound_set_clause.cpp normalized_query_part.cpp normalized_single_query.cpp query_graph.cpp) diff --git a/src/binder/query/bound_set_clause.cpp b/src/binder/query/bound_set_clause.cpp new file mode 100644 index 0000000000..e7dc58f698 --- /dev/null +++ b/src/binder/query/bound_set_clause.cpp @@ -0,0 +1,33 @@ +#include "binder/query/updating_clause/bound_set_clause.h" + +namespace kuzu { +namespace binder { + +expression_vector BoundSetClause::getPropertiesToRead() const { + expression_vector result; + for (auto& setNodeProperty : setNodeProperties) { + for (auto& property : setNodeProperty->getSetItem().second->getSubPropertyExpressions()) { + result.push_back(property); + } + } + for (auto& setRelProperty : setRelProperties) { + for (auto& property : setRelProperty->getSetItem().second->getSubPropertyExpressions()) { + result.push_back(property); + } + } + return result; +} + +unique_ptr BoundSetClause::copy() { + auto result = make_unique(); + for (auto& setNodeProperty : setNodeProperties) { + result->addSetNodeProperty(setNodeProperty->copy()); + } + for (auto& setRelProperty : setRelProperties) { + result->addSetRelProperty(setRelProperty->copy()); + } + return result; +} + +} // namespace binder +} // namespace kuzu diff --git a/src/include/binder/binder.h b/src/include/binder/binder.h index 9e81df36fc..0c01e49930 100644 --- a/src/include/binder/binder.h +++ b/src/include/binder/binder.h @@ -3,7 +3,6 @@ #include "binder/query/bound_regular_query.h" #include "common/csv_reader/csv_reader.h" #include "expression_binder.h" -#include "parser/ddl/create_rel_clause.h" #include "parser/query/regular_query.h" #include "query_normalizer.h" @@ -15,7 +14,10 @@ namespace binder { class BoundCreateNode; class BoundCreateRel; +class BoundSetNodeProperty; +class BoundSetRelProperty; class BoundDeleteNode; +class SetItem; class Binder { friend class ExpressionBinder; @@ -76,6 +78,11 @@ class Binder { shared_ptr node, const PropertyKeyValCollection& collection); unique_ptr bindCreateRel( shared_ptr rel, const PropertyKeyValCollection& collection); + unique_ptr bindSetNodeProperty( + shared_ptr node, pair setItem); + unique_ptr bindSetRelProperty( + shared_ptr rel, pair setItem); + expression_pair bindSetItem(pair setItem); unique_ptr bindDeleteNode(shared_ptr node); shared_ptr bindDeleteRel(shared_ptr rel); diff --git a/src/include/binder/query/updating_clause/bound_set_clause.h b/src/include/binder/query/updating_clause/bound_set_clause.h index 1606c08be7..07c94e4d89 100644 --- a/src/include/binder/query/updating_clause/bound_set_clause.h +++ b/src/include/binder/query/updating_clause/bound_set_clause.h @@ -1,39 +1,72 @@ #pragma once +#include "binder/expression/rel_expression.h" #include "bound_updating_clause.h" namespace kuzu { namespace binder { -class BoundSetClause : public BoundUpdatingClause { +class BoundSetNodeProperty { +public: + BoundSetNodeProperty(shared_ptr node, expression_pair setItem) + : node{std::move(node)}, setItem{std::move(setItem)} {} + + inline shared_ptr getNode() const { return node; } + inline expression_pair getSetItem() const { return setItem; } + inline unique_ptr copy() const { + return make_unique(node, setItem); + } + +private: + shared_ptr node; + expression_pair setItem; +}; + +class BoundSetRelProperty { public: - BoundSetClause() : BoundUpdatingClause{ClauseType::SET} {}; + BoundSetRelProperty(shared_ptr rel, expression_pair setItem) + : rel{std::move(rel)}, setItem{std::move(setItem)} {} - inline void addSetItem(expression_pair setItem) { setItems.push_back(std::move(setItem)); } + inline shared_ptr getRel() const { return rel; } + inline expression_pair getSetItem() const { return setItem; } - inline expression_vector getPropertiesToRead() const override { - expression_vector result; - for (auto& setItem : setItems) { - for (auto& property : setItem.second->getSubPropertyExpressions()) { - result.push_back(property); - } - } - return result; + inline unique_ptr copy() const { + return make_unique(rel, setItem); } - inline vector getSetItems() const { return setItems; } +private: + shared_ptr rel; + expression_pair setItem; +}; - inline unique_ptr copy() override { - auto result = make_unique(); - for (auto& setItem : setItems) { - result->addSetItem(setItem); - } - return result; +class BoundSetClause : public BoundUpdatingClause { +public: + BoundSetClause() : BoundUpdatingClause{ClauseType::SET} {}; + + inline void addSetNodeProperty(unique_ptr setNodeProperty) { + setNodeProperties.push_back(std::move(setNodeProperty)); + } + inline bool hasSetNodeProperty() const { return !setNodeProperties.empty(); } + inline const vector>& getSetNodeProperties() const { + return setNodeProperties; } + inline void addSetRelProperty(unique_ptr setRelProperty) { + setRelProperties.push_back(std::move(setRelProperty)); + } + inline bool hasSetRelProperty() const { return !setRelProperties.empty(); } + inline const vector>& getSetRelProperties() const { + return setRelProperties; + } + + expression_vector getPropertiesToRead() const override; + + unique_ptr copy() override; + private: - vector setItems; + vector> setNodeProperties; + vector> setRelProperties; }; } // namespace binder diff --git a/src/include/parser/query/updating_clause/set_clause.h b/src/include/parser/query/updating_clause/set_clause.h index d3f6e7cd41..c62d0ec1a8 100644 --- a/src/include/parser/query/updating_clause/set_clause.h +++ b/src/include/parser/query/updating_clause/set_clause.h @@ -6,27 +6,22 @@ namespace kuzu { namespace parser { -struct SetItem { - - SetItem(unique_ptr origin, unique_ptr target) - : origin{move(origin)}, target{move(target)} {} - - unique_ptr origin; - unique_ptr target; -}; - class SetClause : public UpdatingClause { - public: SetClause() : UpdatingClause{ClauseType::SET} {}; ~SetClause() override = default; - inline void addSetItem(unique_ptr setItem) { setItems.push_back(move(setItem)); } + inline void addSetItem( + pair, unique_ptr> setItem) { + setItems.push_back(std::move(setItem)); + } inline uint32_t getNumSetItems() const { return setItems.size(); } - inline SetItem* getSetItem(uint32_t idx) const { return setItems[idx].get(); } + inline pair getSetItem(uint32_t idx) const { + return make_pair(setItems[idx].first.get(), setItems[idx].second.get()); + } private: - vector> setItems; + vector, unique_ptr>> setItems; }; } // namespace parser diff --git a/src/include/parser/transformer.h b/src/include/parser/transformer.h index f9c5962adb..fb5497d789 100644 --- a/src/include/parser/transformer.h +++ b/src/include/parser/transformer.h @@ -43,7 +43,8 @@ class Transformer { unique_ptr transformSet(CypherParser::OC_SetContext& ctx); - unique_ptr transformSetItem(CypherParser::OC_SetItemContext& ctx); + pair, unique_ptr> transformSetItem( + CypherParser::OC_SetItemContext& ctx); unique_ptr transformDelete(CypherParser::OC_DeleteContext& ctx); diff --git a/src/include/planner/logical_plan/logical_operator/base_logical_operator.h b/src/include/planner/logical_plan/logical_operator/base_logical_operator.h index d3dda4ffe1..f088260d21 100644 --- a/src/include/planner/logical_plan/logical_operator/base_logical_operator.h +++ b/src/include/planner/logical_plan/logical_operator/base_logical_operator.h @@ -36,6 +36,7 @@ enum class LogicalOperatorType : uint8_t { SCAN_NODE_PROPERTY, SEMI_MASKER, SET_NODE_PROPERTY, + SET_REL_PROPERTY, SKIP, UNION_ALL, UNWIND, diff --git a/src/include/planner/logical_plan/logical_operator/logical_create.h b/src/include/planner/logical_plan/logical_operator/logical_create.h index 17455fe208..2f65e322f7 100644 --- a/src/include/planner/logical_plan/logical_operator/logical_create.h +++ b/src/include/planner/logical_plan/logical_operator/logical_create.h @@ -1,32 +1,37 @@ #pragma once -#include "logical_create_delete.h" +#include "logical_update.h" namespace kuzu { namespace planner { -class LogicalCreateNode : public LogicalCreateOrDeleteNode { +class LogicalCreateNode : public LogicalUpdateNode { public: - LogicalCreateNode( - vector, shared_ptr>> nodeAndPrimaryKeys, + LogicalCreateNode(vector> nodes, expression_vector primaryKeys, shared_ptr child) - : LogicalCreateOrDeleteNode{ - LogicalOperatorType::CREATE_NODE, std::move(nodeAndPrimaryKeys), std::move(child)} {} + : LogicalUpdateNode{LogicalOperatorType::CREATE_NODE, std::move(nodes), std::move(child)}, + primaryKeys{std::move(primaryKeys)} {} + ~LogicalCreateNode() override = default; void computeSchema() override; + inline shared_ptr getPrimaryKey(size_t idx) const { return primaryKeys[idx]; } + inline unique_ptr copy() override { - return make_unique(nodeAndPrimaryKeys, children[0]->copy()); + return make_unique(nodes, primaryKeys, children[0]->copy()); } + +private: + expression_vector primaryKeys; }; -class LogicalCreateRel : public LogicalCreateOrDeleteRel { +class LogicalCreateRel : public LogicalUpdateRel { public: LogicalCreateRel(vector> rels, vector> setItemsPerRel, shared_ptr child) - : LogicalCreateOrDeleteRel{LogicalOperatorType::CREATE_REL, std::move(rels), - std::move(child)}, + : LogicalUpdateRel{LogicalOperatorType::CREATE_REL, std::move(rels), std::move(child)}, setItemsPerRel{std::move(setItemsPerRel)} {} + ~LogicalCreateRel() override = default; inline vector getSetItems(uint32_t idx) const { return setItemsPerRel[idx]; } diff --git a/src/include/planner/logical_plan/logical_operator/logical_delete.h b/src/include/planner/logical_plan/logical_operator/logical_delete.h index 1b5628235c..b27b26835a 100644 --- a/src/include/planner/logical_plan/logical_operator/logical_delete.h +++ b/src/include/planner/logical_plan/logical_operator/logical_delete.h @@ -1,32 +1,35 @@ #pragma once -#include "logical_create_delete.h" +#include "logical_update.h" using namespace kuzu::binder; namespace kuzu { namespace planner { -class LogicalDeleteNode : public LogicalCreateOrDeleteNode { +class LogicalDeleteNode : public LogicalUpdateNode { public: - LogicalDeleteNode( - vector, shared_ptr>> nodeAndPrimaryKeys, + LogicalDeleteNode(vector> nodes, expression_vector primaryKeys, shared_ptr child) - : LogicalCreateOrDeleteNode{ - LogicalOperatorType::DELETE_NODE, std::move(nodeAndPrimaryKeys), std::move(child)} {} + : LogicalUpdateNode{LogicalOperatorType::DELETE_NODE, std::move(nodes), std::move(child)}, + primaryKeys{std::move(primaryKeys)} {} + ~LogicalDeleteNode() override = default; - inline void computeSchema() override { copyChildSchema(0); } + inline shared_ptr getPrimaryKey(size_t idx) const { return primaryKeys[idx]; } inline unique_ptr copy() override { - return make_unique(nodeAndPrimaryKeys, children[0]->copy()); + return make_unique(nodes, primaryKeys, children[0]->copy()); } + +private: + expression_vector primaryKeys; }; -class LogicalDeleteRel : public LogicalCreateOrDeleteRel { +class LogicalDeleteRel : public LogicalUpdateRel { public: LogicalDeleteRel(vector> rels, shared_ptr child) - : LogicalCreateOrDeleteRel{ - LogicalOperatorType::DELETE_REL, std::move(rels), std::move(child)} {} + : LogicalUpdateRel{LogicalOperatorType::DELETE_REL, std::move(rels), std::move(child)} {} + ~LogicalDeleteRel() override = default; inline unique_ptr copy() override { return make_unique(rels, children[0]->copy()); diff --git a/src/include/planner/logical_plan/logical_operator/logical_set.h b/src/include/planner/logical_plan/logical_operator/logical_set.h index f78f70abfa..14f12304b1 100644 --- a/src/include/planner/logical_plan/logical_operator/logical_set.h +++ b/src/include/planner/logical_plan/logical_operator/logical_set.h @@ -1,35 +1,59 @@ #pragma once -#include "base_logical_operator.h" -#include "binder/expression/expression.h" +#include "logical_update.h" namespace kuzu { namespace planner { -class LogicalSetNodeProperty : public LogicalOperator { +class LogicalSetNodeProperty : public LogicalUpdateNode { public: - LogicalSetNodeProperty(vector setItems, shared_ptr child) - : LogicalOperator{LogicalOperatorType::SET_NODE_PROPERTY, std::move(child)}, + LogicalSetNodeProperty(vector> nodes, + vector setItems, shared_ptr child) + : LogicalUpdateNode{LogicalOperatorType::SET_NODE_PROPERTY, std::move(nodes), + std::move(child)}, setItems{std::move(setItems)} {} - inline void computeSchema() override { copyChildSchema(0); } + inline string getExpressionsForPrinting() const override { + string result; + for (auto& [lhs, rhs] : setItems) { + result += lhs->getRawName() + " = " + rhs->getRawName() + ","; + } + return result; + } + + inline expression_pair getSetItem(size_t idx) const { return setItems[idx]; } + + inline unique_ptr copy() override { + return make_unique(nodes, setItems, children[0]->copy()); + } + +private: + vector setItems; +}; + +class LogicalSetRelProperty : public LogicalUpdateRel { +public: + LogicalSetRelProperty(vector> rels, vector setItems, + shared_ptr child) + : LogicalUpdateRel{LogicalOperatorType::SET_REL_PROPERTY, std::move(rels), + std::move(child)}, + setItems{std::move(setItems)} {} inline string getExpressionsForPrinting() const override { string result; - for (auto& [propertyExpression, expression] : setItems) { - result += propertyExpression->getRawName() + " = " + expression->getRawName() + ","; + for (auto& [lhs, rhs] : setItems) { + result += lhs->getRawName() + " = " + rhs->getRawName() + ","; } return result; } - inline vector getSetItems() const { return setItems; } + inline expression_pair getSetItem(size_t idx) const { return setItems[idx]; } inline unique_ptr copy() override { - return make_unique(setItems, children[0]->copy()); + return make_unique(rels, setItems, children[0]->copy()); } private: - // Property expression = target expression pair. vector setItems; }; diff --git a/src/include/planner/logical_plan/logical_operator/logical_create_delete.h b/src/include/planner/logical_plan/logical_operator/logical_update.h similarity index 56% rename from src/include/planner/logical_plan/logical_operator/logical_create_delete.h rename to src/include/planner/logical_plan/logical_operator/logical_update.h index d8176bb9a6..321238a19d 100644 --- a/src/include/planner/logical_plan/logical_operator/logical_create_delete.h +++ b/src/include/planner/logical_plan/logical_operator/logical_update.h @@ -6,38 +6,38 @@ namespace kuzu { namespace planner { -class LogicalCreateOrDeleteNode : public LogicalOperator { +class LogicalUpdateNode : public LogicalOperator { public: - LogicalCreateOrDeleteNode(LogicalOperatorType operatorType, - vector, shared_ptr>> nodeAndPrimaryKeys, + LogicalUpdateNode(LogicalOperatorType operatorType, vector> nodes, shared_ptr child) - : LogicalOperator{operatorType, std::move(child)}, nodeAndPrimaryKeys{ - std::move(nodeAndPrimaryKeys)} {} + : LogicalOperator{operatorType, std::move(child)}, nodes{std::move(nodes)} {} + ~LogicalUpdateNode() override = default; + + inline void computeSchema() override { copyChildSchema(0); } inline string getExpressionsForPrinting() const override { expression_vector expressions; - for (auto& [node, primaryKey] : nodeAndPrimaryKeys) { + for (auto& node : nodes) { expressions.push_back(node); } return ExpressionUtil::toString(expressions); } - inline vector, shared_ptr>> - getNodeAndPrimaryKeys() const { - return nodeAndPrimaryKeys; - } + inline size_t getNumNodes() const { return nodes.size(); } + inline shared_ptr getNode(uint32_t idx) const { return nodes[idx]; } unique_ptr copy() override = 0; protected: - vector, shared_ptr>> nodeAndPrimaryKeys; + vector> nodes; }; -class LogicalCreateOrDeleteRel : public LogicalOperator { +class LogicalUpdateRel : public LogicalOperator { public: - LogicalCreateOrDeleteRel(LogicalOperatorType operatorType, - vector> rels, shared_ptr child) + LogicalUpdateRel(LogicalOperatorType operatorType, vector> rels, + shared_ptr child) : LogicalOperator{operatorType, std::move(child)}, rels{std::move(rels)} {} + ~LogicalUpdateRel() override = default; inline void computeSchema() override { copyChildSchema(0); } diff --git a/src/include/planner/update_planner.h b/src/include/planner/update_planner.h index 49e7e1cb79..2aab061d17 100644 --- a/src/include/planner/update_planner.h +++ b/src/include/planner/update_planner.h @@ -23,22 +23,24 @@ class UpdatePlanner { private: void planUpdatingClause(BoundUpdatingClause& updatingClause, LogicalPlan& plan); - void planSetItem(expression_pair setItem, LogicalPlan& plan); void planCreate(BoundCreateClause& createClause, LogicalPlan& plan); void appendCreateNode( const vector>& createNodes, LogicalPlan& plan); void appendCreateRel(const vector>& createRels, LogicalPlan& plan); - inline void appendSet(BoundSetClause& setClause, LogicalPlan& plan) { - appendSet(setClause.getSetItems(), plan); - } - void appendSet(vector setItems, LogicalPlan& plan); + void planSet(BoundSetClause& setClause, LogicalPlan& plan); + void appendSetNodeProperty( + const vector>& setNodeProperties, LogicalPlan& plan); + void appendSetRelProperty( + const vector>& setRelProperties, LogicalPlan& plan); void planDelete(BoundDeleteClause& deleteClause, LogicalPlan& plan); void appendDeleteNode( const vector>& deleteNodes, LogicalPlan& plan); void appendDeleteRel(const vector>& deleteRels, LogicalPlan& plan); + + void flattenRel(const RelExpression& rel, LogicalPlan& plan); }; } // namespace planner diff --git a/src/include/processor/mapper/plan_mapper.h b/src/include/processor/mapper/plan_mapper.h index 3cc25e7977..3b084f8607 100644 --- a/src/include/processor/mapper/plan_mapper.h +++ b/src/include/processor/mapper/plan_mapper.h @@ -57,7 +57,10 @@ class PlanMapper { unique_ptr mapLogicalFTableScanToPhysical(LogicalOperator* logicalOperator); unique_ptr mapLogicalCreateNodeToPhysical(LogicalOperator* logicalOperator); unique_ptr mapLogicalCreateRelToPhysical(LogicalOperator* logicalOperator); - unique_ptr mapLogicalSetToPhysical(LogicalOperator* logicalOperator); + unique_ptr mapLogicalSetNodePropertyToPhysical( + LogicalOperator* logicalOperator); + unique_ptr mapLogicalSetRelPropertyToPhysical( + LogicalOperator* logicalOperator); unique_ptr mapLogicalDeleteNodeToPhysical(LogicalOperator* logicalOperator); unique_ptr mapLogicalDeleteRelToPhysical(LogicalOperator* logicalOperator); unique_ptr mapLogicalCreateNodeTableToPhysical( diff --git a/src/include/processor/operator/physical_operator.h b/src/include/processor/operator/physical_operator.h index ea58e0aa93..171bc2c55a 100644 --- a/src/include/processor/operator/physical_operator.h +++ b/src/include/processor/operator/physical_operator.h @@ -41,6 +41,7 @@ enum class PhysicalOperatorType : uint8_t { SCAN_NODE_PROPERTY, SEMI_MASKER, SET_NODE_PROPERTY, + SET_REL_PROPERTY, SKIP, ORDER_BY, ORDER_BY_MERGE, @@ -118,7 +119,7 @@ class PhysicalOperator { protected: virtual void initGlobalStateInternal(ExecutionContext* context) {} - virtual void initLocalStateInternal(ResultSet* _resultSet, ExecutionContext* context) {} + virtual void initLocalStateInternal(ResultSet* resultSet_, ExecutionContext* context) {} // Return false if no more tuples to pull, otherwise return true virtual bool getNextTuplesInternal() = 0; diff --git a/src/include/processor/operator/update/set.h b/src/include/processor/operator/update/set.h index 66a9ef7142..b20f2a2154 100644 --- a/src/include/processor/operator/update/set.h +++ b/src/include/processor/operator/update/set.h @@ -3,50 +3,91 @@ #include "expression_evaluator/base_evaluator.h" #include "processor/operator/physical_operator.h" #include "storage/storage_structure/column.h" +#include "storage/store/rel_table.h" using namespace kuzu::evaluator; namespace kuzu { namespace processor { -class BaseSetNodeProperty : public PhysicalOperator { -protected: - BaseSetNodeProperty(vector nodeIDPositions, - vector> expressionEvaluators, +struct SetNodePropertyInfo { + Column* column; + DataPos nodeIDPos; + unique_ptr evaluator; + + SetNodePropertyInfo( + Column* column, const DataPos& nodeIDPos, unique_ptr evaluator) + : column{column}, nodeIDPos{nodeIDPos}, evaluator{std::move(evaluator)} {} + + inline unique_ptr clone() const { + return make_unique(column, nodeIDPos, evaluator->clone()); + } +}; + +class SetNodeProperty : public PhysicalOperator { +public: + SetNodeProperty(vector> infos, unique_ptr child, uint32_t id, const string& paramsString) : PhysicalOperator{PhysicalOperatorType::SET_NODE_PROPERTY, std::move(child), id, paramsString}, - nodeIDPositions{std::move(nodeIDPositions)}, expressionEvaluators{ - std::move(expressionEvaluators)} {} - virtual ~BaseSetNodeProperty() override = default; + infos{std::move(infos)} {} + + ~SetNodeProperty() override = default; void initLocalStateInternal(ResultSet* resultSet, ExecutionContext* context) override; - bool getNextTuplesInternal() override = 0; + bool getNextTuplesInternal() override; - unique_ptr clone() override = 0; + unique_ptr clone() override; + +private: + vector> infos; -protected: - vector nodeIDPositions; vector> nodeIDVectors; - vector> expressionEvaluators; }; -class SetNodeStructuredProperty : public BaseSetNodeProperty { +struct SetRelPropertyInfo { + RelTable* table; + DataPos srcNodePos; + DataPos dstNodePos; + DataPos relIDPos; + // TODO(Ziyi): see issue 1122 and do a typedef on our column & list idx. + uint64_t propertyId; + unique_ptr evaluator; + + SetRelPropertyInfo(RelTable* table, const DataPos& srcNodePos, const DataPos& dstNodePos, + const DataPos& relIDPos, uint64_t propertyId, unique_ptr evaluator) + : table{table}, srcNodePos{srcNodePos}, dstNodePos{dstNodePos}, relIDPos{relIDPos}, + propertyId{propertyId}, evaluator{std::move(evaluator)} {} + + inline unique_ptr clone() const { + return make_unique( + table, srcNodePos, dstNodePos, relIDPos, propertyId, evaluator->clone()); + } +}; + +class SetRelProperty : public PhysicalOperator { public: - SetNodeStructuredProperty(vector nodeIDPositions, - vector> expressionEvaluators, vector columns, - unique_ptr child, uint32_t id, const string& paramsString) - : BaseSetNodeProperty{std::move(nodeIDPositions), std::move(expressionEvaluators), - std::move(child), id, paramsString}, - columns{std::move(columns)} {} + SetRelProperty(vector> infos, unique_ptr child, + uint32_t id, const string& paramsString) + : PhysicalOperator{PhysicalOperatorType::SET_NODE_PROPERTY, std::move(child), id, + paramsString}, + infos{std::move(infos)} {} + + ~SetRelProperty() override = default; + + void initLocalStateInternal(ResultSet* resultSet, ExecutionContext* context) override; bool getNextTuplesInternal() override; unique_ptr clone() override; private: - vector columns; + vector> infos; + + vector> srcNodeVectors; + vector> dstNodeVectors; + vector> relIDVectors; }; } // namespace processor diff --git a/src/parser/transformer.cpp b/src/parser/transformer.cpp index 93b8373bb1..556be48f51 100644 --- a/src/parser/transformer.cpp +++ b/src/parser/transformer.cpp @@ -146,8 +146,9 @@ unique_ptr Transformer::transformSet(CypherParser::OC_SetContext return setClause; } -unique_ptr Transformer::transformSetItem(CypherParser::OC_SetItemContext& ctx) { - return make_unique( +pair, unique_ptr> Transformer::transformSetItem( + CypherParser::OC_SetItemContext& ctx) { + return make_pair( transformProperty(*ctx.oC_PropertyExpression()), transformExpression(*ctx.oC_Expression())); } diff --git a/src/planner/operator/base_logical_operator.cpp b/src/planner/operator/base_logical_operator.cpp index 742cc9b97b..d07edd70be 100644 --- a/src/planner/operator/base_logical_operator.cpp +++ b/src/planner/operator/base_logical_operator.cpp @@ -91,6 +91,9 @@ std::string LogicalOperatorUtils::logicalOperatorTypeToString(LogicalOperatorTyp case LogicalOperatorType::SET_NODE_PROPERTY: { return "SET_NODE_PROPERTY"; } + case LogicalOperatorType::SET_REL_PROPERTY: { + return "SET_REL_PROPERTY"; + } case LogicalOperatorType::SKIP: { return "SKIP"; } diff --git a/src/planner/operator/logical_create.cpp b/src/planner/operator/logical_create.cpp index a6b1f5f56d..bb80eb0fe0 100644 --- a/src/planner/operator/logical_create.cpp +++ b/src/planner/operator/logical_create.cpp @@ -4,8 +4,8 @@ namespace kuzu { namespace planner { void LogicalCreateNode::computeSchema() { - copyChildSchema(0); - for (auto& [node, _] : nodeAndPrimaryKeys) { + LogicalUpdateNode::computeSchema(); + for (auto& node : nodes) { auto groupPos = schema->createGroup(); schema->setGroupAsSingleState(groupPos); schema->insertToGroupAndScope(node->getInternalIDProperty(), groupPos); diff --git a/src/planner/update_planner.cpp b/src/planner/update_planner.cpp index 0daf333b2f..21183991c5 100644 --- a/src/planner/update_planner.cpp +++ b/src/planner/update_planner.cpp @@ -27,7 +27,7 @@ void UpdatePlanner::planUpdatingClause(BoundUpdatingClause& updatingClause, Logi } case ClauseType::SET: { QueryPlanner::appendAccumulate(plan); - appendSet((BoundSetClause&)updatingClause, plan); + planSet((BoundSetClause&)updatingClause, plan); return; } case ClauseType::DELETE: { @@ -40,26 +40,6 @@ void UpdatePlanner::planUpdatingClause(BoundUpdatingClause& updatingClause, Logi } } -void UpdatePlanner::planSetItem(expression_pair setItem, LogicalPlan& plan) { - auto lhs = setItem.first; - auto rhs = setItem.second; - // Check LHS - assert(lhs->getChild(0)->dataType.typeID == NODE); - auto nodeExpression = static_pointer_cast(lhs->getChild(0)); - auto lhsGroupPos = plan.getSchema()->getGroupPos(nodeExpression->getInternalIDPropertyName()); - auto isLhsFlat = plan.getSchema()->getGroup(lhsGroupPos)->isFlat(); - // Check RHS - auto rhsDependentGroupsPos = plan.getSchema()->getDependentGroupsPos(rhs); - if (!rhsDependentGroupsPos.empty()) { // RHS is not constant - auto rhsPos = QueryPlanner::appendFlattensButOne(rhsDependentGroupsPos, plan); - auto isRhsFlat = plan.getSchema()->getGroup(rhsPos)->isFlat(); - // If both are unflat and from different groups, we flatten LHS. - if (!isRhsFlat && !isLhsFlat && lhsGroupPos != rhsPos) { - QueryPlanner::appendFlattenIfNecessary(lhsGroupPos, plan); - } - } -} - void UpdatePlanner::planCreate(BoundCreateClause& createClause, LogicalPlan& plan) { // Flatten all inputs. E.g. MATCH (a) CREATE (b). We need to create b for each tuple in the // match clause. This is to simplify operator implementation. @@ -76,20 +56,22 @@ void UpdatePlanner::planCreate(BoundCreateClause& createClause, LogicalPlan& pla void UpdatePlanner::appendCreateNode( const vector>& createNodes, LogicalPlan& plan) { - vector setItems; - vector, shared_ptr>> nodeAndPrimaryKeyPairs; + vector> nodes; + expression_vector primaryKeys; + vector> setNodeProperties; for (auto& createNode : createNodes) { auto node = createNode->getNode(); - nodeAndPrimaryKeyPairs.emplace_back(node, createNode->getPrimaryKeyExpression()); + nodes.push_back(node); + primaryKeys.push_back(createNode->getPrimaryKeyExpression()); for (auto& setItem : createNode->getSetItems()) { - setItems.push_back(setItem); + setNodeProperties.push_back(make_unique(node, setItem)); } } - auto createNode = - make_shared(std::move(nodeAndPrimaryKeyPairs), plan.getLastOperator()); + auto createNode = make_shared( + std::move(nodes), std::move(primaryKeys), plan.getLastOperator()); createNode->computeSchema(); plan.setLastOperator(createNode); - appendSet(std::move(setItems), plan); + appendSetNodeProperty(setNodeProperties, plan); } void UpdatePlanner::appendCreateRel( @@ -106,16 +88,58 @@ void UpdatePlanner::appendCreateRel( plan.setLastOperator(createRel); } -void UpdatePlanner::appendSet(vector setItems, LogicalPlan& plan) { - if (setItems.empty()) { - return; +void UpdatePlanner::planSet(BoundSetClause& setClause, LogicalPlan& plan) { + if (setClause.hasSetNodeProperty()) { + appendSetNodeProperty(setClause.getSetNodeProperties(), plan); + } + if (setClause.hasSetRelProperty()) { + appendSetRelProperty(setClause.getSetRelProperties(), plan); } - for (auto& setItem : setItems) { - planSetItem(setItem, plan); +} + +void UpdatePlanner::appendSetNodeProperty( + const vector>& setNodeProperties, LogicalPlan& plan) { + vector> nodes; + vector setItems; + for (auto& setNodeProperty : setNodeProperties) { + auto node = setNodeProperty->getNode(); + auto lhsGroupPos = plan.getSchema()->getGroupPos(node->getInternalIDPropertyName()); + auto isLhsFlat = plan.getSchema()->getGroup(lhsGroupPos)->isFlat(); + auto rhs = setNodeProperty->getSetItem().second; + auto rhsDependentGroupsPos = plan.getSchema()->getDependentGroupsPos(rhs); + if (!rhsDependentGroupsPos.empty()) { // RHS is not constant + auto rhsPos = QueryPlanner::appendFlattensButOne(rhsDependentGroupsPos, plan); + auto isRhsFlat = plan.getSchema()->getGroup(rhsPos)->isFlat(); + // If both are unflat and from different groups, we flatten LHS. + if (!isRhsFlat && !isLhsFlat && lhsGroupPos != rhsPos) { + QueryPlanner::appendFlattenIfNecessary(lhsGroupPos, plan); + } + } + nodes.push_back(node); + setItems.push_back(setNodeProperty->getSetItem()); } - auto setNode = make_shared(std::move(setItems), plan.getLastOperator()); - setNode->computeSchema(); - plan.setLastOperator(std::move(setNode)); + auto setNodeProperty = make_shared( + std::move(nodes), std::move(setItems), plan.getLastOperator()); + setNodeProperty->computeSchema(); + plan.setLastOperator(setNodeProperty); +} + +void UpdatePlanner::appendSetRelProperty( + const vector>& setRelProperties, LogicalPlan& plan) { + vector> rels; + vector setItems; + for (auto& setRelProperty : setRelProperties) { + flattenRel(*setRelProperty->getRel(), plan); + auto rhs = setRelProperty->getSetItem().second; + auto rhsDependentGroupsPos = plan.getSchema()->getDependentGroupsPos(rhs); + QueryPlanner::appendFlattens(rhsDependentGroupsPos, plan); + rels.push_back(setRelProperty->getRel()); + setItems.push_back(setRelProperty->getSetItem()); + } + auto setRelProperty = make_shared( + std::move(rels), std::move(setItems), plan.getLastOperator()); + setRelProperty->computeSchema(); + plan.setLastOperator(setRelProperty); } void UpdatePlanner::planDelete(BoundDeleteClause& deleteClause, LogicalPlan& plan) { @@ -129,13 +153,14 @@ void UpdatePlanner::planDelete(BoundDeleteClause& deleteClause, LogicalPlan& pla void UpdatePlanner::appendDeleteNode( const vector>& deleteNodes, LogicalPlan& plan) { - vector, shared_ptr>> nodeAndPrimaryKeyPairs; + vector> nodes; + expression_vector primaryKeys; for (auto& deleteNode : deleteNodes) { - nodeAndPrimaryKeyPairs.emplace_back( - deleteNode->getNode(), deleteNode->getPrimaryKeyExpression()); + nodes.push_back(deleteNode->getNode()); + primaryKeys.push_back(deleteNode->getPrimaryKeyExpression()); } - auto deleteNode = - make_shared(std::move(nodeAndPrimaryKeyPairs), plan.getLastOperator()); + auto deleteNode = make_shared( + std::move(nodes), std::move(primaryKeys), plan.getLastOperator()); deleteNode->computeSchema(); plan.setLastOperator(std::move(deleteNode)); } @@ -144,15 +169,19 @@ void UpdatePlanner::appendDeleteRel( const vector>& deleteRels, LogicalPlan& plan) { // Delete one rel at a time so we flatten for each rel. for (auto& rel : deleteRels) { - auto srcNodeID = rel->getSrcNode()->getInternalIDProperty(); - QueryPlanner::appendFlattenIfNecessary(srcNodeID, plan); - auto dstNodeID = rel->getDstNode()->getInternalIDProperty(); - QueryPlanner::appendFlattenIfNecessary(dstNodeID, plan); + flattenRel(*rel, plan); } auto deleteRel = make_shared(deleteRels, plan.getLastOperator()); deleteRel->computeSchema(); plan.setLastOperator(std::move(deleteRel)); } +void UpdatePlanner::flattenRel(const RelExpression& rel, LogicalPlan& plan) { + auto srcNodeID = rel.getSrcNode()->getInternalIDProperty(); + QueryPlanner::appendFlattenIfNecessary(srcNodeID, plan); + auto dstNodeID = rel.getDstNode()->getInternalIDProperty(); + QueryPlanner::appendFlattenIfNecessary(dstNodeID, plan); +} + } // namespace planner } // namespace kuzu diff --git a/src/processor/mapper/map_create.cpp b/src/processor/mapper/map_create.cpp index 21144497cf..cbc99ee326 100644 --- a/src/processor/mapper/map_create.cpp +++ b/src/processor/mapper/map_create.cpp @@ -15,7 +15,9 @@ unique_ptr PlanMapper::mapLogicalCreateNodeToPhysical( auto& nodesStore = storageManager.getNodesStore(); auto catalogContent = catalog->getReadOnlyVersion(); vector> createNodeInfos; - for (auto& [node, primaryKey] : logicalCreateNode->getNodeAndPrimaryKeys()) { + for (auto i = 0u; i < logicalCreateNode->getNumNodes(); ++i) { + auto node = logicalCreateNode->getNode(i); + auto primaryKey = logicalCreateNode->getPrimaryKey(i); auto nodeTableID = node->getSingleTableID(); auto table = nodesStore.getNodeTable(nodeTableID); auto primaryKeyEvaluator = expressionMapper.mapExpression(primaryKey, *inSchema); diff --git a/src/processor/mapper/map_delete.cpp b/src/processor/mapper/map_delete.cpp index 9789798bf1..1537c1fbb7 100644 --- a/src/processor/mapper/map_delete.cpp +++ b/src/processor/mapper/map_delete.cpp @@ -13,7 +13,9 @@ unique_ptr PlanMapper::mapLogicalDeleteNodeToPhysical( auto prevOperator = mapLogicalOperatorToPhysical(logicalOperator->getChild(0)); auto& nodesStore = storageManager.getNodesStore(); vector> deleteNodeInfos; - for (auto& [node, primaryKey] : logicalDeleteNode->getNodeAndPrimaryKeys()) { + for (auto i = 0u; i < logicalDeleteNode->getNumNodes(); ++i) { + auto node = logicalDeleteNode->getNode(i); + auto primaryKey = logicalDeleteNode->getPrimaryKey(i); auto nodeTable = nodesStore.getNodeTable(node->getSingleTableID()); auto nodeIDPos = DataPos(inSchema->getExpressionPos(*node->getInternalIDProperty())); auto primaryKeyPos = DataPos(inSchema->getExpressionPos(*primaryKey)); diff --git a/src/processor/mapper/map_set.cpp b/src/processor/mapper/map_set.cpp index 6b1b862b20..9782a1c574 100644 --- a/src/processor/mapper/map_set.cpp +++ b/src/processor/mapper/map_set.cpp @@ -9,30 +9,53 @@ using namespace kuzu::planner; namespace kuzu { namespace processor { -unique_ptr PlanMapper::mapLogicalSetToPhysical(LogicalOperator* logicalOperator) { +unique_ptr PlanMapper::mapLogicalSetNodePropertyToPhysical( + LogicalOperator* logicalOperator) { auto& logicalSetNodeProperty = (LogicalSetNodeProperty&)*logicalOperator; auto inSchema = logicalSetNodeProperty.getChild(0)->getSchema(); - auto setItems = logicalSetNodeProperty.getSetItems(); auto prevOperator = mapLogicalOperatorToPhysical(logicalOperator->getChild(0)); auto& nodeStore = storageManager.getNodesStore(); - vector> expressionEvaluators; - for (auto& [_, target] : setItems) { - expressionEvaluators.push_back(expressionMapper.mapExpression(target, *inSchema)); - } - vector nodeIDVectorPositions; - vector propertyColumns; - for (auto& [expr, _] : setItems) { - auto property = static_pointer_cast(expr); - auto node = static_pointer_cast(property->getChild(0)); + vector> infos; + for (auto i = 0u; i < logicalSetNodeProperty.getNumNodes(); ++i) { + auto node = logicalSetNodeProperty.getNode(i); + auto [lhs, rhs] = logicalSetNodeProperty.getSetItem(i); + auto nodeIDPos = DataPos(inSchema->getExpressionPos(*node->getInternalIDProperty())); + auto propertyExpression = static_pointer_cast(lhs); auto nodeTableID = node->getSingleTableID(); - nodeIDVectorPositions.emplace_back( - inSchema->getExpressionPos(*node->getInternalIDProperty())); - propertyColumns.push_back( - nodeStore.getNodePropertyColumn(nodeTableID, property->getPropertyID(nodeTableID))); + auto column = nodeStore.getNodePropertyColumn( + nodeTableID, propertyExpression->getPropertyID(nodeTableID)); + auto evaluator = expressionMapper.mapExpression(rhs, *inSchema); + infos.push_back(make_unique(column, nodeIDPos, std::move(evaluator))); + } + return make_unique(std::move(infos), std::move(prevOperator), getOperatorID(), + logicalSetNodeProperty.getExpressionsForPrinting()); +} + +unique_ptr PlanMapper::mapLogicalSetRelPropertyToPhysical( + LogicalOperator* logicalOperator) { + auto& logicalSetRelProperty = (LogicalSetRelProperty&)*logicalOperator; + auto inSchema = logicalSetRelProperty.getChild(0)->getSchema(); + auto prevOperator = mapLogicalOperatorToPhysical(logicalOperator->getChild(0)); + auto& relStore = storageManager.getRelsStore(); + vector> infos; + for (auto i = 0u; i < logicalSetRelProperty.getNumRels(); ++i) { + auto rel = logicalSetRelProperty.getRel(i); + auto [lhs, rhs] = logicalSetRelProperty.getSetItem(i); + auto srcNodePos = + DataPos(inSchema->getExpressionPos(*rel->getSrcNode()->getInternalIDProperty())); + auto dstNodePos = + DataPos(inSchema->getExpressionPos(*rel->getDstNode()->getInternalIDProperty())); + auto relIDPos = DataPos(inSchema->getExpressionPos(*rel->getInternalIDProperty())); + auto relTableID = rel->getSingleTableID(); + auto table = relStore.getRelTable(rel->getSingleTableID()); + auto propertyExpression = static_pointer_cast(lhs); + auto propertyId = propertyExpression->getPropertyID(relTableID); + auto evaluator = expressionMapper.mapExpression(rhs, *inSchema); + infos.push_back(make_unique( + table, srcNodePos, dstNodePos, relIDPos, propertyId, std::move(evaluator))); } - return make_unique(std::move(nodeIDVectorPositions), - std::move(expressionEvaluators), std::move(propertyColumns), std::move(prevOperator), - getOperatorID(), logicalSetNodeProperty.getExpressionsForPrinting()); + return make_unique(std::move(infos), std::move(prevOperator), getOperatorID(), + logicalSetRelProperty.getExpressionsForPrinting()); } } // namespace processor diff --git a/src/processor/mapper/plan_mapper.cpp b/src/processor/mapper/plan_mapper.cpp index 4ee03e6c96..ca913e4187 100644 --- a/src/processor/mapper/plan_mapper.cpp +++ b/src/processor/mapper/plan_mapper.cpp @@ -95,7 +95,10 @@ unique_ptr PlanMapper::mapLogicalOperatorToPhysical( physicalOperator = mapLogicalCreateRelToPhysical(logicalOperator.get()); } break; case LogicalOperatorType::SET_NODE_PROPERTY: { - physicalOperator = mapLogicalSetToPhysical(logicalOperator.get()); + physicalOperator = mapLogicalSetNodePropertyToPhysical(logicalOperator.get()); + } break; + case LogicalOperatorType::SET_REL_PROPERTY: { + physicalOperator = mapLogicalSetRelPropertyToPhysical(logicalOperator.get()); } break; case LogicalOperatorType::DELETE_NODE: { physicalOperator = mapLogicalDeleteNodeToPhysical(logicalOperator.get()); diff --git a/src/processor/operator/physical_operator.cpp b/src/processor/operator/physical_operator.cpp index 3c2c21cc22..fee82ce91a 100644 --- a/src/processor/operator/physical_operator.cpp +++ b/src/processor/operator/physical_operator.cpp @@ -105,6 +105,9 @@ std::string PhysicalOperatorUtils::operatorTypeToString(PhysicalOperatorType ope case PhysicalOperatorType::SET_NODE_PROPERTY: { return "SET_NODE_PROPERTY"; } + case PhysicalOperatorType::SET_REL_PROPERTY: { + return "SET_REL_PROPERTY"; + } case PhysicalOperatorType::SKIP: { return "SKIP"; } @@ -170,15 +173,15 @@ void PhysicalOperator::initGlobalState(ExecutionContext* context) { initGlobalStateInternal(context); } -void PhysicalOperator::initLocalState(ResultSet* _resultSet, ExecutionContext* context) { +void PhysicalOperator::initLocalState(ResultSet* resultSet_, ExecutionContext* context) { if (!children.empty()) { assert(children.size() == 1); - children[0]->initLocalState(_resultSet, context); + children[0]->initLocalState(resultSet_, context); } transaction = context->transaction; - resultSet = _resultSet; + resultSet = resultSet_; registerProfilingMetrics(context->profiler); - initLocalStateInternal(_resultSet, context); + initLocalStateInternal(resultSet_, context); } void PhysicalOperator::registerProfilingMetrics(Profiler* profiler) { diff --git a/src/processor/operator/update/set.cpp b/src/processor/operator/update/set.cpp index c5e298c8a1..0c3fecee70 100644 --- a/src/processor/operator/update/set.cpp +++ b/src/processor/operator/update/set.cpp @@ -3,34 +3,61 @@ namespace kuzu { namespace processor { -void BaseSetNodeProperty::initLocalStateInternal(ResultSet* resultSet, ExecutionContext* context) { - for (auto& pos : nodeIDPositions) { - auto nodeIDVector = resultSet->getValueVector(pos); - nodeIDVectors.push_back(std::move(nodeIDVector)); - } - for (auto& expressionEvaluator : expressionEvaluators) { - expressionEvaluator->init(*resultSet, context->memoryManager); +void SetNodeProperty::initLocalStateInternal(ResultSet* resultSet, ExecutionContext* context) { + for (auto& info : infos) { + auto nodeIDVector = resultSet->getValueVector(info->nodeIDPos); + nodeIDVectors.push_back(nodeIDVector); + info->evaluator->init(*resultSet, context->memoryManager); } } -bool SetNodeStructuredProperty::getNextTuplesInternal() { +bool SetNodeProperty::getNextTuplesInternal() { if (!children[0]->getNextTuple()) { return false; } - for (auto i = 0u; i < nodeIDVectors.size(); ++i) { - expressionEvaluators[i]->evaluate(); - columns[i]->writeValues(nodeIDVectors[i], expressionEvaluators[i]->resultVector); + for (auto i = 0u; i < infos.size(); ++i) { + auto info = infos[i].get(); + info->evaluator->evaluate(); + info->column->writeValues(nodeIDVectors[i], info->evaluator->resultVector); } return true; } -unique_ptr SetNodeStructuredProperty::clone() { - vector> clonedExpressionEvaluators; - for (auto& expressionEvaluator : expressionEvaluators) { - clonedExpressionEvaluators.push_back(expressionEvaluator->clone()); +unique_ptr SetNodeProperty::clone() { + vector> clonedInfos; + for (auto& info : infos) { + clonedInfos.push_back(info->clone()); + } + return make_unique( + std::move(clonedInfos), children[0]->clone(), id, paramsString); +} + +void SetRelProperty::initLocalStateInternal(ResultSet* resultSet, ExecutionContext* context) { + for (auto& info : infos) { + auto srcNodeIDVector = resultSet->getValueVector(info->srcNodePos); + srcNodeVectors.push_back(srcNodeIDVector); + auto dstNodeIDVector = resultSet->getValueVector(info->dstNodePos); + dstNodeVectors.push_back(dstNodeIDVector); + auto relIDVector = resultSet->getValueVector(info->relIDPos); + relIDVectors.push_back(relIDVector); + info->evaluator->init(*resultSet, context->memoryManager); + } +} + +bool SetRelProperty::getNextTuplesInternal() { + if (!children[0]->getNextTuple()) { + return false; + } + throw NotImplementedException("Unimplemented SetRelProperty."); +} + +unique_ptr SetRelProperty::clone() { + vector> clonedInfos; + for (auto& info : infos) { + clonedInfos.push_back(info->clone()); } - return make_unique(nodeIDPositions, - std::move(clonedExpressionEvaluators), columns, children[0]->clone(), id, paramsString); + return make_unique( + std::move(clonedInfos), children[0]->clone(), id, paramsString); } } // namespace processor diff --git a/test/runner/e2e_exception_test.cpp b/test/runner/e2e_exception_test.cpp index b4118256d3..b4129a7382 100644 --- a/test/runner/e2e_exception_test.cpp +++ b/test/runner/e2e_exception_test.cpp @@ -225,6 +225,7 @@ TEST_F(TinySnbExceptionTest, MultiLabelUpdate) { "Binder exception: Set property of node a with multiple node labels is not supported."); result = conn->query( "MATCH (a:person:organisation)-[e:knows]->(b:person) SET e.date=date('2022-12-12')"); - ASSERT_STREQ( - result->getErrorMessage().c_str(), "Binder exception: Set REL property is supported."); + ASSERT_STREQ(result->getErrorMessage().c_str(), + "Binder exception: Set property of rel e with multiple rel labels or bound by multiple " + "node labels is not supported."); }