@@ -265,6 +265,18 @@ PartialUpdateMergeFunction::CreateFieldAggregators(
265265 return aggregators;
266266}
267267
268+ void PartialUpdateMergeFunction::Reset () {
269+ current_key_.reset ();
270+ meet_insert_ = false ;
271+ not_null_column_filled_ = false ;
272+ row_ = std::make_unique<GenericRow>(getters_.size ());
273+ last_seq_num_ = 0 ;
274+ for (auto & [_, agg] : field_aggregators_) {
275+ assert (agg);
276+ agg->Reset ();
277+ }
278+ }
279+
268280Status PartialUpdateMergeFunction::Add (KeyValue&& moved_kv) {
269281 // refresh key object to avoid reference overwritten
270282 KeyValue kv = std::move (moved_kv);
@@ -275,33 +287,50 @@ Status PartialUpdateMergeFunction::Add(KeyValue&& moved_kv) {
275287 // In 0.7- versions, the delete records might be written into data file even when
276288 // ignore-delete configured, so ignoreDelete still needs to be checked
277289 if (ignore_delete_) {
290+ if (!not_null_column_filled_) {
291+ InitRowAndHoldData (std::move (kv.value ));
292+ not_null_column_filled_ = true ;
293+ }
278294 return Status::OK ();
279295 }
296+
297+ last_seq_num_ = kv.sequence_number ;
298+
280299 if (field_sequence_enabled_) {
300+ // RetractWithSequenceGroup handles InitRow and AddDataHolder internally
281301 PAIMON_RETURN_NOT_OK (RetractWithSequenceGroup (std::move (kv)));
282302 return Status::OK ();
283303 }
284304 if (remove_record_on_delete_) {
285305 if (kv.value_kind == RowKind::Delete ()) {
286306 current_delete_row_ = true ;
287307 row_ = std::make_unique<GenericRow>(getters_.size ());
308+ InitRowAndHoldData (std::move (kv.value ));
309+ } else if (!not_null_column_filled_) {
310+ InitRowAndHoldData (std::move (kv.value ));
311+ not_null_column_filled_ = true ;
288312 }
289313 return Status::OK ();
290314 }
291315
292316 return Status::Invalid (
293317 " By default, Partial update can not accept delete records, you can choose one of "
294- " the following solutions:1. Configure ignore-delete to ignore delete records; 2. "
295- " Configure partial-update.remove-record-on-delete to remove the whole row when "
296- " receiving delete records; 3. Configure sequence-group to retract partial "
297- " columns." );
318+ " the following solutions:\n "
319+ " 1. Configure 'ignore-delete' to ignore delete records.\n "
320+ " 2. Configure 'partial-update.remove-record-on-delete' to remove the whole row "
321+ " when receiving delete records.\n "
322+ " 3. Configure 'sequence-group's to retract partial columns. Also configure "
323+ " 'partial-update.remove-record-on-sequence-group' to remove the whole row when "
324+ " receiving deleted records of specified sequence group." );
298325 }
299326 last_seq_num_ = kv.sequence_number ;
300327 if (field_comparators_.empty ()) {
301328 UpdateNonNullFields (std::move (kv));
302329 } else {
303330 UpdateWithSequenceGroup (std::move (kv));
304331 }
332+ meet_insert_ = true ;
333+ not_null_column_filled_ = true ;
305334 return Status::OK ();
306335}
307336
@@ -356,6 +385,15 @@ void PartialUpdateMergeFunction::UpdateWithSequenceGroup(KeyValue&& kv) {
356385}
357386
358387Status PartialUpdateMergeFunction::RetractWithSequenceGroup (KeyValue&& kv) {
388+ // Initialize row with all field values if this is the first record.
389+ // InitRow only reads field values (string_view etc.) from kv.value without taking ownership.
390+ // kv.value remains alive throughout this method, so the views are safe until AddDataHolder
391+ // at the end transfers ownership to row_.
392+ if (!not_null_column_filled_) {
393+ InitRow (*(kv.value ));
394+ not_null_column_filled_ = true ;
395+ }
396+
359397 std::set<int32_t > updated_sequence_fields;
360398 for (size_t i = 0 ; i < getters_.size (); ++i) {
361399 auto cmp_iter = field_comparators_.find (i);
@@ -382,6 +420,7 @@ Status PartialUpdateMergeFunction::RetractWithSequenceGroup(KeyValue&& kv) {
382420 sequence_group_partial_delete_.end ()) {
383421 current_delete_row_ = true ;
384422 row_ = std::make_unique<GenericRow>(getters_.size ());
423+ InitRowAndHoldData (std::move (kv.value ));
385424 return Status::OK ();
386425 } else {
387426 row_->SetField (field_idx, getters_[field_idx](*(kv.value )));
@@ -413,6 +452,18 @@ Status PartialUpdateMergeFunction::RetractWithSequenceGroup(KeyValue&& kv) {
413452 return Status::OK ();
414453}
415454
455+ void PartialUpdateMergeFunction::InitRow (const InternalRow& value) {
456+ for (size_t i = 0 ; i < getters_.size (); ++i) {
457+ VariantType field = getters_[i](value);
458+ row_->SetField (i, field);
459+ }
460+ }
461+
462+ void PartialUpdateMergeFunction::InitRowAndHoldData (std::unique_ptr<InternalRow>&& value) {
463+ InitRow (*value);
464+ row_->AddDataHolder (std::move (value));
465+ }
466+
416467bool PartialUpdateMergeFunction::IsEmptySequenceGroup (
417468 const KeyValue& kv, const std::shared_ptr<FieldsComparator>& comparator) const {
418469 for (const auto & field_idx : comparator->CompareFields ()) {
0 commit comments