@@ -177,13 +177,11 @@ TEST_F(PartialUpdateMergeFunctionTest, TestSequenceGroupPartialDelete) {
177177 Add (mfunc, RowKind::Delete (), {1 , 1 , 1 , 3 , 1 , 1 , NullType ()});
178178 CheckResult (mfunc, {1 , NullType (), NullType (), 3 , 3 , 3 , 3 });
179179 Add (mfunc, RowKind::Delete (), {1 , 1 , 1 , 3 , 1 , 1 , 4 });
180- CheckResult (mfunc, {NullType (), NullType (), NullType (), NullType (), NullType (), NullType (),
181- NullType ()});
180+ CheckResult (mfunc, {1 , 1 , 1 , 3 , 1 , 1 , 4 });
182181 Add (mfunc, {1 , 4 , 4 , 4 , 5 , 5 , 5 });
183182 CheckResult (mfunc, {1 , 4 , 4 , 4 , 5 , 5 , 5 });
184183 Add (mfunc, RowKind::Delete (), {1 , 1 , 1 , 6 , 1 , 1 , 6 });
185- CheckResult (mfunc, {NullType (), NullType (), NullType (), NullType (), NullType (), NullType (),
186- NullType ()});
184+ CheckResult (mfunc, {1 , 1 , 1 , 6 , 1 , 1 , 6 });
187185}
188186
189187TEST_F (PartialUpdateMergeFunctionTest, TestMultiSequenceFields) {
@@ -794,4 +792,84 @@ TEST_F(PartialUpdateMergeFunctionTest, TestCreateFieldAggregatorsWithoutDefaultA
794792 // test no agg: f2
795793 ASSERT_TRUE (aggs.find (3 ) == aggs.end ());
796794}
795+
796+ TEST_F (PartialUpdateMergeFunctionTest, TestSequenceGroupPartialDeleteWithProjection) {
797+ std::map<std::string, std::string> options_map = {
798+ {" fields.f3.sequence-group" , " f1,f2" },
799+ {" fields.f6.sequence-group" , " f4,f5" },
800+ {" partial-update.remove-record-on-sequence-group" , " f3,f6" }};
801+
802+ auto table_fields = CreateDataFields (/* value_arity=*/ 7 );
803+ // Reordered fields: f3, f6, f0, f1, f2, f4, f5
804+ std::vector<DataField> value_fields = {table_fields[3 ], table_fields[6 ], table_fields[0 ],
805+ table_fields[1 ], table_fields[2 ], table_fields[4 ],
806+ table_fields[5 ]};
807+ std::vector<DataField> expected_completed_value_fields = value_fields;
808+
809+ auto mfunc = CreateMergeFunctionWithProjection (table_fields, value_fields, options_map,
810+ expected_completed_value_fields);
811+ mfunc->Reset ();
812+ // Reordered: f3=11, f6=22, f0=100, f1=200, f2=1, f4=12, f5=21
813+ Add (mfunc, {11 , 22 , 100 , 200 , 1 , 12 , 21 });
814+ Add (mfunc, RowKind::Delete (), {11 , 22 , 100 , 200 , 1 , 12 , 21 });
815+ CheckResult (mfunc, {11 , 22 , 100 , 200 , 1 , 12 , 21 });
816+ }
817+
818+ TEST_F (PartialUpdateMergeFunctionTest, TestAdjustProjectionNonProject) {
819+ std::map<std::string, std::string> options_map = {{" fields.f4.sequence-group" , " f1,f3" },
820+ {" fields.f5.sequence-group" , " f7" }};
821+ auto table_fields = CreateDataFields (/* value_arity=*/ 8 );
822+ // Non-projection: use all fields
823+ std::vector<DataField> value_fields = table_fields;
824+ std::vector<DataField> expected_completed_value_fields = table_fields;
825+
826+ auto mfunc = CreateMergeFunctionWithProjection (table_fields, value_fields, options_map,
827+ expected_completed_value_fields);
828+ mfunc->Reset ();
829+ Add (mfunc, {1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 });
830+ Add (mfunc, {4 , 2 , 4 , 2 , 2 , 0 , NullType (), 3 });
831+ CheckResult (mfunc, {4 , 2 , 4 , 2 , 2 , 1 , 1 , 1 });
832+ }
833+
834+ TEST_F (PartialUpdateMergeFunctionTest, TestDeleteReproduceCorrectSequenceNumber) {
835+ std::map<std::string, std::string> options_map = {
836+ {" partial-update.remove-record-on-delete" , " true" }};
837+ auto mfunc = CreateMergeFunction (/* value_arity=*/ 5 , options_map);
838+ mfunc->Reset ();
839+
840+ Add (mfunc, {1 , 1 , 1 , 1 , 1 });
841+ Add (mfunc, RowKind::Delete (), {1 , 1 , 1 , 1 , 1 });
842+
843+ ASSERT_OK_AND_ASSIGN (auto result, mfunc->GetResult ());
844+ ASSERT_TRUE (result.has_value ());
845+ ASSERT_EQ (result->sequence_number , 1 );
846+ }
847+
848+ TEST_F (PartialUpdateMergeFunctionTest, TestInitRowWithNullableFieldOnDelete) {
849+ std::map<std::string, std::string> options_map = {
850+ {" partial-update.remove-record-on-delete" , " true" }};
851+ // f0 and f1 are not nullable, f2 and f3 are nullable
852+ std::vector<DataField> data_fields = {
853+ DataField (0 , arrow::field (" f0" , arrow::int32 (), /* nullable=*/ false )),
854+ DataField (1 , arrow::field (" f1" , arrow::int32 (), /* nullable=*/ false )),
855+ DataField (2 , arrow::field (" f2" , arrow::int32 (), /* nullable=*/ true )),
856+ DataField (3 , arrow::field (" f3" , arrow::int32 (), /* nullable=*/ true ))};
857+ auto value_schema = DataField::ConvertDataFieldsToArrowSchema (data_fields);
858+ ASSERT_OK_AND_ASSIGN (CoreOptions options, CoreOptions::FromMap (options_map));
859+ std::map<std::string, std::vector<std::string>> value_field_to_seq_group_field;
860+ std::set<std::string> seq_group_key_set;
861+ ASSERT_OK (PartialUpdateMergeFunction::ParseSequenceGroupFields (
862+ options, &value_field_to_seq_group_field, &seq_group_key_set));
863+ ASSERT_OK_AND_ASSIGN (auto mfunc, PartialUpdateMergeFunction::Create (
864+ value_schema, /* primary_keys=*/ {" f0" }, options,
865+ value_field_to_seq_group_field, seq_group_key_set));
866+ mfunc->Reset ();
867+
868+ // insert some data first
869+ Add (mfunc, {1 , 3 , 5 , 7 });
870+ // send a DELETE with nullable field as null, triggers initRow
871+ Add (mfunc, RowKind::Delete (), {1 , 2 , 2 , NullType ()});
872+ // after delete with removeRecordOnDelete, row is re-initialized via initRow
873+ CheckResult (mfunc, {1 , 2 , 2 , NullType ()});
874+ }
797875} // namespace paimon::test
0 commit comments