diff --git a/src/binder/bind/bind_updating_clause.cpp b/src/binder/bind/bind_updating_clause.cpp index 5f4ccf52e2..a1dc5f577b 100644 --- a/src/binder/bind/bind_updating_clause.cpp +++ b/src/binder/bind/bind_updating_clause.cpp @@ -150,9 +150,8 @@ std::unique_ptr Binder::bindCreateNodeInfo( throw BinderException("Create node " + node->toString() + " expects primary key " + primaryKey->getName() + " as input."); } - auto extraInfo = std::make_unique(std::move(primaryKeyExpression)); return std::make_unique( - UpdateTableType::NODE, std::move(node), std::move(setItems), std::move(extraInfo)); + UpdateTableType::NODE, std::move(node), std::move(setItems)); } std::unique_ptr Binder::bindCreateRelInfo( @@ -180,7 +179,7 @@ std::unique_ptr Binder::bindCreateRelInfo( } } return std::make_unique( - UpdateTableType::REL, std::move(rel), std::move(setItems), nullptr /* extraInfo */); + UpdateTableType::REL, std::move(rel), std::move(setItems)); } std::unique_ptr Binder::bindSetClause(const UpdatingClause& updatingClause) { diff --git a/src/include/binder/query/updating_clause/bound_create_info.h b/src/include/binder/query/updating_clause/bound_create_info.h index 903960f192..2b855c8474 100644 --- a/src/include/binder/query/updating_clause/bound_create_info.h +++ b/src/include/binder/query/updating_clause/bound_create_info.h @@ -6,40 +6,18 @@ namespace kuzu { namespace binder { -struct ExtraCreateInfo { - virtual ~ExtraCreateInfo() = default; - virtual std::unique_ptr copy() const = 0; -}; - -struct ExtraCreateNodeInfo : public ExtraCreateInfo { - std::shared_ptr primaryKey; - - explicit ExtraCreateNodeInfo(std::shared_ptr primaryKey) - : primaryKey{std::move(primaryKey)} {} - ExtraCreateNodeInfo(const ExtraCreateNodeInfo& other) : primaryKey{other.primaryKey} {} - - inline std::unique_ptr copy() const final { - return std::make_unique(*this); - } -}; - struct BoundCreateInfo { UpdateTableType updateTableType; std::shared_ptr nodeOrRel; std::vector setItems; - std::unique_ptr extraInfo; BoundCreateInfo(UpdateTableType updateTableType, std::shared_ptr nodeOrRel, - std::vector setItems, std::unique_ptr extraInfo) - : updateTableType{updateTableType}, nodeOrRel{std::move(nodeOrRel)}, - setItems{std::move(setItems)}, extraInfo{std::move(extraInfo)} {} + std::vector setItems) + : updateTableType{updateTableType}, nodeOrRel{std::move(nodeOrRel)}, setItems{std::move( + setItems)} {} BoundCreateInfo(const BoundCreateInfo& other) : updateTableType{other.updateTableType}, nodeOrRel{other.nodeOrRel}, setItems{ - other.setItems} { - if (other.extraInfo) { - extraInfo = other.extraInfo->copy(); - } - } + other.setItems} {} inline std::unique_ptr copy() { return std::make_unique(*this); diff --git a/src/include/planner/logical_plan/persistent/logical_create.h b/src/include/planner/logical_plan/persistent/logical_create.h index ccc2904d31..e084c7065b 100644 --- a/src/include/planner/logical_plan/persistent/logical_create.h +++ b/src/include/planner/logical_plan/persistent/logical_create.h @@ -8,17 +8,16 @@ namespace planner { struct LogicalCreateNodeInfo { std::shared_ptr node; - std::shared_ptr primaryKey; + std::vector setItems; binder::expression_vector propertiesToReturn; LogicalCreateNodeInfo(std::shared_ptr node, - std::shared_ptr primaryKey, - binder::expression_vector propertiesToReturn) - : node{std::move(node)}, primaryKey{std::move(primaryKey)}, propertiesToReturn{std::move( - propertiesToReturn)} {} + std::vector setItems, binder::expression_vector propertiesToReturn) + : node{std::move(node)}, setItems{std::move(setItems)}, propertiesToReturn{std::move( + propertiesToReturn)} {} LogicalCreateNodeInfo(const LogicalCreateNodeInfo& other) - : node{other.node}, primaryKey{other.primaryKey}, propertiesToReturn{ - other.propertiesToReturn} {} + : node{other.node}, setItems{other.setItems}, propertiesToReturn{other.propertiesToReturn} { + } inline std::unique_ptr copy() const { return std::make_unique(*this); diff --git a/src/include/processor/operator/persistent/insert_executor.h b/src/include/processor/operator/persistent/insert_executor.h index 9377f18630..956a92b156 100644 --- a/src/include/processor/operator/persistent/insert_executor.h +++ b/src/include/processor/operator/persistent/insert_executor.h @@ -10,11 +10,14 @@ namespace processor { // TODO(Guodong): the following class should be moved to storage. class NodeInsertExecutor { public: - NodeInsertExecutor(storage::NodeTable* table, - std::unique_ptr primaryKeyEvaluator, - std::vector relTablesToInit, const DataPos& outNodeIDVectorPos) - : table{table}, primaryKeyEvaluator{std::move(primaryKeyEvaluator)}, - relTablesToInit{std::move(relTablesToInit)}, outNodeIDVectorPos{outNodeIDVectorPos} {} + NodeInsertExecutor(storage::NodeTable* table, std::vector relTablesToInit, + const DataPos& nodeIDVectorPos, std::vector propertyLhsPositions, + std::vector> propertyRhsEvaluators, + std::unordered_map propertyIDToVectorIdx) + : table{table}, relTablesToInit{std::move(relTablesToInit)}, + nodeIDVectorPos{nodeIDVectorPos}, propertyLhsPositions{std::move(propertyLhsPositions)}, + propertyRhsEvaluators{std::move(propertyRhsEvaluators)}, propertyIDToVectorIdx{std::move( + propertyIDToVectorIdx)} {} NodeInsertExecutor(const NodeInsertExecutor& other); void init(ResultSet* resultSet, ExecutionContext* context); @@ -30,23 +33,27 @@ class NodeInsertExecutor { private: storage::NodeTable* table; - std::unique_ptr primaryKeyEvaluator; std::vector relTablesToInit; - DataPos outNodeIDVectorPos; - - common::ValueVector* primaryKeyVector = nullptr; - common::ValueVector* outNodeIDVector = nullptr; + DataPos nodeIDVectorPos; + std::vector propertyLhsPositions; + std::vector> propertyRhsEvaluators; + // TODO(Guodong): remove this. + std::unordered_map propertyIDToVectorIdx; + + common::ValueVector* nodeIDVector; + std::vector propertyLhsVectors; + std::vector propertyRhsVectors; }; class RelInsertExecutor { public: RelInsertExecutor(storage::RelsStatistics& relsStatistics, storage::RelTable* table, const DataPos& srcNodePos, const DataPos& dstNodePos, - std::vector lhsVectorPositions, - std::vector> evaluators) + std::vector propertyLhsPositions, + std::vector> propertyRhsEvaluators) : relsStatistics{relsStatistics}, table{table}, srcNodePos{srcNodePos}, - dstNodePos{dstNodePos}, lhsVectorPositions{std::move(lhsVectorPositions)}, - evaluators{std::move(evaluators)} {} + dstNodePos{dstNodePos}, propertyLhsPositions{std::move(propertyLhsPositions)}, + propertyRhsEvaluators{std::move(propertyRhsEvaluators)} {} RelInsertExecutor(const RelInsertExecutor& other); void init(ResultSet* resultSet, ExecutionContext* context); @@ -65,13 +72,13 @@ class RelInsertExecutor { storage::RelTable* table; DataPos srcNodePos; DataPos dstNodePos; - std::vector lhsVectorPositions; - std::vector> evaluators; + std::vector propertyLhsPositions; + std::vector> propertyRhsEvaluators; common::ValueVector* srcNodeIDVector = nullptr; common::ValueVector* dstNodeIDVector = nullptr; - std::vector lhsVectors; - std::vector rhsVectors; + std::vector propertyLhsVectors; + std::vector propertyRhsVectors; }; } // namespace processor diff --git a/src/include/storage/store/node_table.h b/src/include/storage/store/node_table.h index a26dfea2b8..af7f933c24 100644 --- a/src/include/storage/store/node_table.h +++ b/src/include/storage/store/node_table.h @@ -37,7 +37,11 @@ class NodeTable { void read(transaction::Transaction* transaction, common::ValueVector* nodeIDVector, const std::vector& columnIds, const std::vector& outputVectors); - common::offset_t insert(transaction::Transaction* transaction, common::ValueVector* primaryKey); + void insert(transaction::Transaction* transaction, common::ValueVector* nodeIDVector, + const std::vector& propertyVectors, + const std::unordered_map& + propertyIDToVectorIdx); + void update(common::property_id_t propertyID, common::ValueVector* nodeIDVector, common::ValueVector* vectorToWriteFrom); void delete_(transaction::Transaction* transaction, common::ValueVector* nodeIDVector, @@ -82,14 +86,14 @@ class NodeTable { const std::vector& columnIds, const std::vector& outputVectors); - void setPropertiesToNull(common::offset_t offset); - void insertPK(common::offset_t offset, common::ValueVector* primaryKeyVector); + void insertPK(common::ValueVector* nodeIDVector, common::ValueVector* primaryKeyVector); inline uint64_t getNumNodeGroups(transaction::Transaction* transaction) const { return propertyColumns.begin()->second->getNumNodeGroups(transaction); } private: NodesStatisticsAndDeletedIDs* nodesStatisticsAndDeletedIDs; + // TODO(Guodong): use vector here std::map> propertyColumns; BMFileHandle* dataFH; BMFileHandle* metadataFH; diff --git a/src/include/storage/store/rel_table.h b/src/include/storage/store/rel_table.h index 23f0f514df..7fc9f0f5e0 100644 --- a/src/include/storage/store/rel_table.h +++ b/src/include/storage/store/rel_table.h @@ -222,7 +222,7 @@ class RelTable { common::ValueVector* relIDVector); void updateRel(common::ValueVector* srcNodeIDVector, common::ValueVector* dstNodeIDVector, common::ValueVector* relIDVector, common::ValueVector* propertyVector, uint32_t propertyID); - void initEmptyRelsForNewNode(common::nodeID_t& nodeID); + void initEmptyRelsForNewNode(common::ValueVector* nodeIDVector); void batchInitEmptyRelsForNewNodes(common::table_id_t relTableID, uint64_t numNodesInTable); void addProperty(const catalog::Property& property, catalog::RelTableSchema& relTableSchema); diff --git a/src/optimizer/projection_push_down_optimizer.cpp b/src/optimizer/projection_push_down_optimizer.cpp index a2a71c0020..4147aff2b4 100644 --- a/src/optimizer/projection_push_down_optimizer.cpp +++ b/src/optimizer/projection_push_down_optimizer.cpp @@ -162,8 +162,8 @@ void ProjectionPushDownOptimizer::visitUnwind(planner::LogicalOperator* op) { void ProjectionPushDownOptimizer::visitCreateNode(planner::LogicalOperator* op) { auto createNode = (LogicalCreateNode*)op; for (auto& info : createNode->getInfosRef()) { - if (info->primaryKey != nullptr) { - collectExpressionsInUse(info->primaryKey); + for (auto& setItem : info->setItems) { + collectExpressionsInUse(setItem.second); } } } @@ -202,8 +202,8 @@ void ProjectionPushDownOptimizer::visitMerge(planner::LogicalOperator* op) { auto merge = (LogicalMerge*)op; collectExpressionsInUse(merge->getMark()); for (auto& info : merge->getCreateNodeInfosRef()) { - if (info->primaryKey != nullptr) { - collectExpressionsInUse(info->primaryKey); + for (auto& setItem : info->setItems) { + collectExpressionsInUse(setItem.second); } } for (auto& info : merge->getCreateRelInfosRef()) { diff --git a/src/planner/plan/append_create.cpp b/src/planner/plan/append_create.cpp index 44189ccfc9..f20e73945e 100644 --- a/src/planner/plan/append_create.cpp +++ b/src/planner/plan/append_create.cpp @@ -12,9 +12,8 @@ std::unique_ptr QueryPlanner::createLogicalCreateNodeInfo BoundCreateInfo* boundCreateInfo) { auto node = std::static_pointer_cast(boundCreateInfo->nodeOrRel); auto propertiesToReturn = getProperties(*node); - auto extraInfo = (ExtraCreateNodeInfo*)boundCreateInfo->extraInfo.get(); return std::make_unique( - node, extraInfo->primaryKey, std::move(propertiesToReturn)); + node, boundCreateInfo->setItems, std::move(propertiesToReturn)); } std::unique_ptr QueryPlanner::createLogicalCreateRelInfo( @@ -51,13 +50,6 @@ void QueryPlanner::appendCreateNode( createNode->setChild(0, plan.getLastOperator()); createNode->computeFactorizedSchema(); plan.setLastOperator(createNode); - // Apply SET after CREATE - auto boundSetNodePropertyInfos = createLogicalSetPropertyInfo(boundCreateInfos); - std::vector setInfoPtrs; - for (auto& setInfo : boundSetNodePropertyInfos) { - setInfoPtrs.push_back(setInfo.get()); - } - appendSetNodeProperty(setInfoPtrs, plan); } void QueryPlanner::appendCreateRel( diff --git a/src/processor/map/map_create.cpp b/src/processor/map/map_create.cpp index 3b9291f57a..d8216ee69c 100644 --- a/src/processor/map/map_create.cpp +++ b/src/processor/map/map_create.cpp @@ -11,6 +11,19 @@ using namespace kuzu::catalog; namespace kuzu { namespace processor { +static std::vector populateLhsVectorPositions( + const std::vector& setItems, const Schema& outSchema) { + std::vector result; + for (auto& [lhs, rhs] : setItems) { + if (outSchema.isExpressionInScope(*lhs)) { + result.emplace_back(outSchema.getExpressionPos(*lhs)); + } else { + result.emplace_back(INVALID_DATA_CHUNK_POS, INVALID_DATA_CHUNK_POS); + } + } + return result; +} + std::unique_ptr PlanMapper::getNodeInsertExecutor( storage::NodesStore* nodesStore, storage::RelsStore* relsStore, planner::LogicalCreateNodeInfo* info, const planner::Schema& inSchema, @@ -18,10 +31,6 @@ std::unique_ptr PlanMapper::getNodeInsertExecutor( auto node = info->node; auto nodeTableID = node->getSingleTableID(); auto table = nodesStore->getNodeTable(nodeTableID); - std::unique_ptr evaluator = nullptr; - if (info->primaryKey != nullptr) { - evaluator = expressionMapper.mapExpression(info->primaryKey, inSchema); - } std::vector relTablesToInit; for (auto& schema : catalog->getReadOnlyVersion()->getRelTableSchemas()) { if (schema->isSrcOrDstTable(nodeTableID)) { @@ -29,8 +38,17 @@ std::unique_ptr PlanMapper::getNodeInsertExecutor( } } auto nodeIDPos = DataPos(outSchema.getExpressionPos(*node->getInternalIDProperty())); - return std::make_unique( - table, std::move(evaluator), std::move(relTablesToInit), nodeIDPos); + std::vector lhsVectorPositions = populateLhsVectorPositions(info->setItems, outSchema); + std::vector> evaluators; + std::unordered_map propertyIDToVectorIdx; + for (auto i = 0u; i < info->setItems.size(); ++i) { + auto& [lhs, rhs] = info->setItems[i]; + auto propertyExpression = (binder::PropertyExpression*)lhs.get(); + evaluators.push_back(expressionMapper.mapExpression(rhs, inSchema)); + propertyIDToVectorIdx.insert({propertyExpression->getPropertyID(nodeTableID), i}); + } + return std::make_unique(table, std::move(relTablesToInit), nodeIDPos, + std::move(lhsVectorPositions), std::move(evaluators), std::move(propertyIDToVectorIdx)); } std::unique_ptr PlanMapper::mapCreateNode(LogicalOperator* logicalOperator) { @@ -57,14 +75,9 @@ std::unique_ptr PlanMapper::getRelInsertExecutor(storage::Rel auto dstNode = rel->getDstNode(); auto srcNodePos = DataPos(inSchema.getExpressionPos(*srcNode->getInternalIDProperty())); auto dstNodePos = DataPos(inSchema.getExpressionPos(*dstNode->getInternalIDProperty())); - std::vector lhsVectorPositions; + auto lhsVectorPositions = populateLhsVectorPositions(info->setItems, outSchema); std::vector> evaluators; for (auto& [lhs, rhs] : info->setItems) { - if (outSchema.isExpressionInScope(*lhs)) { - lhsVectorPositions.emplace_back(outSchema.getExpressionPos(*lhs)); - } else { - lhsVectorPositions.emplace_back(INVALID_DATA_CHUNK_POS, INVALID_DATA_CHUNK_POS); - } evaluators.push_back(expressionMapper.mapExpression(rhs, inSchema)); } return std::make_unique(relsStore->getRelsStatistics(), table, srcNodePos, diff --git a/src/processor/operator/persistent/insert_executor.cpp b/src/processor/operator/persistent/insert_executor.cpp index f84b6402b2..9af659f126 100644 --- a/src/processor/operator/persistent/insert_executor.cpp +++ b/src/processor/operator/persistent/insert_executor.cpp @@ -6,33 +6,60 @@ namespace kuzu { namespace processor { NodeInsertExecutor::NodeInsertExecutor(const NodeInsertExecutor& other) - : table{other.table}, relTablesToInit{other.relTablesToInit}, outNodeIDVectorPos{ - other.outNodeIDVectorPos} { - if (other.primaryKeyEvaluator != nullptr) { - primaryKeyEvaluator = other.primaryKeyEvaluator->clone(); + : table{other.table}, relTablesToInit{other.relTablesToInit}, + nodeIDVectorPos{other.nodeIDVectorPos}, propertyLhsPositions{other.propertyLhsPositions}, + propertyIDToVectorIdx{other.propertyIDToVectorIdx} { + for (auto& evaluator : other.propertyRhsEvaluators) { + propertyRhsEvaluators.push_back(evaluator->clone()); } } void NodeInsertExecutor::init(ResultSet* resultSet, ExecutionContext* context) { - if (primaryKeyEvaluator != nullptr) { - primaryKeyEvaluator->init(*resultSet, context->memoryManager); - primaryKeyVector = primaryKeyEvaluator->resultVector.get(); + nodeIDVector = resultSet->getValueVector(nodeIDVectorPos).get(); + for (auto& pos : propertyLhsPositions) { + if (pos.dataChunkPos != INVALID_DATA_CHUNK_POS) { + propertyLhsVectors.push_back(resultSet->getValueVector(pos).get()); + } else { + propertyLhsVectors.push_back(nullptr); + } + } + for (auto& evaluator : propertyRhsEvaluators) { + evaluator->init(*resultSet, context->memoryManager); + propertyRhsVectors.push_back(evaluator->resultVector.get()); + } +} + +// TODO: consider move to storage +static void writeLhsVectors(const std::vector& lhsVectors, + const std::vector& rhsVectors) { + for (auto i = 0u; i < lhsVectors.size(); ++i) { + auto lhsVector = lhsVectors[i]; + auto rhsVector = rhsVectors[i]; + if (lhsVector == nullptr) { + continue; + } + assert(lhsVector->state->selVector->selectedSize == 1 && + rhsVector->state->selVector->selectedSize == 1); + auto lhsPos = lhsVector->state->selVector->selectedPositions[0]; + auto rhsPos = rhsVector->state->selVector->selectedPositions[0]; + if (rhsVector->isNull(rhsPos)) { + lhsVector->setNull(lhsPos, true); + } else { + lhsVector->setNull(lhsPos, false); + lhsVector->copyFromVectorData(lhsPos, rhsVector, rhsPos); + } } - outNodeIDVector = resultSet->getValueVector(outNodeIDVectorPos).get(); } void NodeInsertExecutor::insert(transaction::Transaction* transaction) { - if (primaryKeyEvaluator != nullptr) { - primaryKeyEvaluator->evaluate(); + for (auto& evaluator : propertyRhsEvaluators) { + evaluator->evaluate(); } - auto offset = table->insert(transaction, primaryKeyVector); - nodeID_t nodeID{offset, table->getTableID()}; - assert(outNodeIDVector->state->selVector->selectedSize == 1); - auto pos = outNodeIDVector->state->selVector->selectedPositions[0]; - outNodeIDVector->setValue(pos, nodeID); + table->insert(transaction, nodeIDVector, propertyRhsVectors, propertyIDToVectorIdx); for (auto& relTable : relTablesToInit) { - relTable->initEmptyRelsForNewNode(nodeID); + relTable->initEmptyRelsForNewNode(nodeIDVector); } + writeLhsVectors(propertyLhsVectors, propertyRhsVectors); } std::vector> NodeInsertExecutor::copy( @@ -47,54 +74,38 @@ std::vector> NodeInsertExecutor::copy( RelInsertExecutor::RelInsertExecutor(const RelInsertExecutor& other) : relsStatistics{other.relsStatistics}, table{other.table}, srcNodePos{other.srcNodePos}, - dstNodePos{other.dstNodePos}, lhsVectorPositions{other.lhsVectorPositions} { - for (auto& evaluator : other.evaluators) { - evaluators.push_back(evaluator->clone()); + dstNodePos{other.dstNodePos}, propertyLhsPositions{other.propertyLhsPositions} { + for (auto& evaluator : other.propertyRhsEvaluators) { + propertyRhsEvaluators.push_back(evaluator->clone()); } } void RelInsertExecutor::init(ResultSet* resultSet, ExecutionContext* context) { srcNodeIDVector = resultSet->getValueVector(srcNodePos).get(); dstNodeIDVector = resultSet->getValueVector(dstNodePos).get(); - for (auto& pos : lhsVectorPositions) { + for (auto& pos : propertyLhsPositions) { if (pos.dataChunkPos != INVALID_DATA_CHUNK_POS) { - lhsVectors.push_back(resultSet->getValueVector(pos).get()); + propertyLhsVectors.push_back(resultSet->getValueVector(pos).get()); } else { - lhsVectors.push_back(nullptr); + propertyLhsVectors.push_back(nullptr); } } - for (auto& evaluator : evaluators) { + for (auto& evaluator : propertyRhsEvaluators) { evaluator->init(*resultSet, context->memoryManager); - rhsVectors.push_back(evaluator->resultVector.get()); + propertyRhsVectors.push_back(evaluator->resultVector.get()); } } void RelInsertExecutor::insert(transaction::Transaction* tx) { auto offset = relsStatistics.getNextRelOffset(tx, table->getRelTableID()); - rhsVectors[0]->setValue(0, offset); - rhsVectors[0]->setNull(0, false); - for (auto i = 1; i < evaluators.size(); ++i) { - evaluators[i]->evaluate(); + propertyRhsVectors[0]->setValue(0, offset); // internal ID property + propertyRhsVectors[0]->setNull(0, false); + for (auto i = 1; i < propertyRhsEvaluators.size(); ++i) { + propertyRhsEvaluators[i]->evaluate(); } - table->insertRel(srcNodeIDVector, dstNodeIDVector, rhsVectors); + table->insertRel(srcNodeIDVector, dstNodeIDVector, propertyRhsVectors); relsStatistics.updateNumRelsByValue(table->getRelTableID(), 1); - for (auto i = 0u; i < lhsVectors.size(); ++i) { - auto lhsVector = lhsVectors[i]; - auto rhsVector = rhsVectors[i]; - if (lhsVector == nullptr) { - continue; - } - assert(lhsVector->state->selVector->selectedSize == 1 && - rhsVector->state->selVector->selectedSize == 1); - auto lhsPos = lhsVector->state->selVector->selectedPositions[0]; - auto rhsPos = rhsVector->state->selVector->selectedPositions[0]; - if (rhsVector->isNull(rhsPos)) { - lhsVector->setNull(lhsPos, true); - } else { - lhsVector->setNull(lhsPos, false); - lhsVector->copyFromVectorData(lhsPos, rhsVector, rhsPos); - } - } + writeLhsVectors(propertyLhsVectors, propertyRhsVectors); } std::vector> RelInsertExecutor::copy( diff --git a/src/storage/store/node_table.cpp b/src/storage/store/node_table.cpp index db767b5832..93ae81973c 100644 --- a/src/storage/store/node_table.cpp +++ b/src/storage/store/node_table.cpp @@ -71,20 +71,31 @@ void NodeTable::lookup(Transaction* transaction, ValueVector* nodeIDVector, } } -offset_t NodeTable::insert(Transaction* transaction, ValueVector* primaryKeyVector) { - auto offset = nodesStatisticsAndDeletedIDs->addNode(tableID); - if (primaryKeyVector) { - assert(pkIndex); - insertPK(offset, primaryKeyVector); +void NodeTable::insert(Transaction* transaction, ValueVector* nodeIDVector, + const std::vector& propertyVectors, + const std::unordered_map& propertyIDToVectorIdx) { + // We assume that offsets are given in the ascending order, thus lastOffset is the max one. + offset_t lastOffset; + for (auto i = 0u; i < nodeIDVector->state->selVector->selectedSize; i++) { + auto pos = nodeIDVector->state->selVector->selectedPositions[i]; + auto offset = nodesStatisticsAndDeletedIDs->addNode(tableID); + nodeIDVector->setValue(pos, nodeID_t{offset, tableID}); + lastOffset = offset; + } + if (pkIndex) { + assert(propertyIDToVectorIdx.contains(pkPropertyID)); + insertPK(nodeIDVector, propertyVectors[propertyIDToVectorIdx.at(pkPropertyID)]); } auto currentNumNodeGroups = getNumNodeGroups(transaction); - if (offset == StorageUtils::getStartOffsetForNodeGroup(currentNumNodeGroups)) { + if (lastOffset >= StorageUtils::getStartOffsetForNodeGroup(currentNumNodeGroups)) { auto newNodeGroup = std::make_unique(this); newNodeGroup->setNodeGroupIdx(currentNumNodeGroups); append(newNodeGroup.get()); } - setPropertiesToNull(offset); - return offset; + for (auto& [propertyID, column] : propertyColumns) { + assert(propertyIDToVectorIdx.contains(propertyID)); + column->write(nodeIDVector, propertyVectors[propertyIDToVectorIdx.at(propertyID)]); + } } void NodeTable::update( @@ -149,23 +160,20 @@ void NodeTable::rollbackInMemory() { pkIndex->rollbackInMemory(); } -void NodeTable::setPropertiesToNull(offset_t offset) { - for (auto& [_, column] : propertyColumns) { - column->setNull(offset); - } -} - -void NodeTable::insertPK(offset_t offset, ValueVector* primaryKeyVector) { - assert(primaryKeyVector->state->selVector->selectedSize == 1); - auto pkValPos = primaryKeyVector->state->selVector->selectedPositions[0]; - if (primaryKeyVector->isNull(pkValPos)) { - throw RuntimeException(ExceptionMessage::nullPKException()); - } - if (!pkIndex->insert(primaryKeyVector, pkValPos, offset)) { - std::string pkStr = primaryKeyVector->dataType.getLogicalTypeID() == LogicalTypeID::INT64 ? - std::to_string(primaryKeyVector->getValue(pkValPos)) : - primaryKeyVector->getValue(pkValPos).getAsString(); - throw RuntimeException(ExceptionMessage::existedPKException(pkStr)); +void NodeTable::insertPK(ValueVector* nodeIDVector, ValueVector* primaryKeyVector) { + for (auto i = 0u; i < nodeIDVector->state->selVector->selectedSize; i++) { + auto pos = nodeIDVector->state->selVector->selectedPositions[i]; + auto offset = nodeIDVector->readNodeOffset(pos); + if (primaryKeyVector->isNull(pos)) { + throw RuntimeException(ExceptionMessage::nullPKException()); + } + if (!pkIndex->insert(primaryKeyVector, pos, offset)) { + std::string pkStr = + primaryKeyVector->dataType.getLogicalTypeID() == LogicalTypeID::INT64 ? + std::to_string(primaryKeyVector->getValue(pos)) : + primaryKeyVector->getValue(pos).getAsString(); + throw RuntimeException(ExceptionMessage::existedPKException(pkStr)); + } } } diff --git a/src/storage/store/rel_table.cpp b/src/storage/store/rel_table.cpp index 2ed1cb8b6d..11e6a2bd54 100644 --- a/src/storage/store/rel_table.cpp +++ b/src/storage/store/rel_table.cpp @@ -334,14 +334,20 @@ void RelTable::updateRel(ValueVector* srcNodeIDVector, ValueVector* dstNodeIDVec listsUpdatesStore->updateRelIfNecessary(srcNodeIDVector, dstNodeIDVector, listsUpdateInfo); } -void RelTable::initEmptyRelsForNewNode(nodeID_t& nodeID) { - if (fwdRelTableData->isSingleMultiplicity() && fwdRelTableData->isBoundTable(nodeID.tableID)) { - fwdRelTableData->getAdjColumn()->setNull(nodeID.offset); - } - if (bwdRelTableData->isSingleMultiplicity() && bwdRelTableData->isBoundTable(nodeID.tableID)) { - bwdRelTableData->getAdjColumn()->setNull(nodeID.offset); +void RelTable::initEmptyRelsForNewNode(ValueVector* nodeIDVector) { + for (auto i = 0u; i < nodeIDVector->state->selVector->selectedSize; i++) { + auto pos = nodeIDVector->state->selVector->selectedPositions[i]; + auto nodeID = nodeIDVector->getValue(pos); + if (fwdRelTableData->isSingleMultiplicity() && + fwdRelTableData->isBoundTable(nodeID.tableID)) { + fwdRelTableData->getAdjColumn()->setNull(nodeID.offset); + } + if (bwdRelTableData->isSingleMultiplicity() && + bwdRelTableData->isBoundTable(nodeID.tableID)) { + bwdRelTableData->getAdjColumn()->setNull(nodeID.offset); + } + listsUpdatesStore->initNewlyAddedNodes(nodeID); } - listsUpdatesStore->initNewlyAddedNodes(nodeID); } void RelTable::batchInitEmptyRelsForNewNodes(table_id_t relTableID, uint64_t numNodesInTable) {