File 1259-mnesia-Do-not-unconditionally-delete-index-keys.patch of Package erlang

From 0835f0bf7a0f897eac6fc0e971ce54538feca175 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Wed, 18 Aug 2021 13:32:08 +0200
Subject: [PATCH] mnesia: Do not unconditionally delete index keys

delete_object(NonExistingRecord) deleted index keys even if the record
didn't exist, in set tables, and nothing was deleted from the real table.

Solve this by doing the same checks as was done for bag tables.

Fixes GH-5040
---
 lib/mnesia/src/mnesia_index.erl              | 23 +++++--------
 lib/mnesia/test/mnesia_trans_access_test.erl | 34 ++++++++++++++++++--
 2 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 2ca6c55870..964c50aa52 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -139,22 +139,15 @@ del_object_index(#index{pos_list = PosL, setorbag = SorB}, Storage, Tab, K, Obj)
     del_object_index2(PosL, SorB, Storage, Tab, K, Obj).
 
 del_object_index2([], _, _Storage, _Tab, _K, _Obj) -> ok;
-del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, K, Obj) ->
+del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, Key, Obj) ->
     ValsF = index_vals_f(Storage, Tab, Pos),
-    case SoB of
-	bag ->
-	    del_object_bag(Type, ValsF, Tab, K, Obj, Ixt);
-	_ -> %% If set remove the tuple in index table
-	    del_ixes(Type, Ixt, ValsF, Obj, K)
-    end,
-    del_object_index2(Tail, SoB, Storage, Tab, K, Obj).
-
-del_object_bag(Type, ValsF, Tab, Key, Obj, Ixt) ->
-    IxKeys = ValsF(Obj),
     Found = [{X, ValsF(X)} || X <- mnesia_lib:db_get(Tab, Key)],
-    del_object_bag_(IxKeys, Found, Type, Tab, Key, Obj, Ixt).
+    IxKeys = ValsF(Obj),
+    del_object_index3(IxKeys, Found, Type, Tab, Key, Obj, Ixt),
+    del_object_index2(Tail, SoB, Storage, Tab, Key, Obj).
+
 
-del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
+del_object_index3([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
     case [X || {X, Ixes} <- Found, lists:member(IxK, Ixes)] of
         [Old] when Old =:= Obj ->
 	    case Type of
@@ -166,8 +159,8 @@ del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
         _ ->
 	    ok
     end,
-    del_object_bag_(IxKs, Found, Type, Tab, Key, Obj, Ixt);
-del_object_bag_([], _, _, _, _, _, _) ->
+    del_object_index3(IxKs, Found, Type, Tab, Key, Obj, Ixt);
+del_object_index3([], _, _, _, _, _, _) ->
     ok.
 
 clear_index(Index, Tab, K, Obj) ->
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index 723a85fd2c..dec396252b 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -77,7 +77,7 @@ groups() ->
        nested_trans_parent_dies, nested_trans_both_dies]},
      {index_tabs, [],
       [index_match_object, index_read, {group, index_update},
-       index_write]},
+       index_write, index_delete_object]},
      {index_update, [],
       [index_update_set, index_update_bag]},
      {index_lifecycle, [],
@@ -1078,6 +1078,36 @@ index_write(Config)when is_list(Config) ->
     ?verify_mnesia(Nodes, []).
 
 
+index_delete_object(suite) -> [];
+index_delete_object(doc) -> ["See issue: GH-5040"];
+index_delete_object(Config) when is_list(Config) ->
+    Nodes = ?acquire_nodes(1, Config),
+    {atomic, ok} = mnesia:create_table(ram_set,[{index, [ix]}, {attributes, [key, ix, val]},
+                                                {ram_copies, Nodes}]),
+    {atomic, ok} = mnesia:create_table(do_set, [{index, [ix]}, {attributes, [key, ix, val]},
+                                                {disc_only_copies, Nodes}]),
+    {atomic, ok} = mnesia:create_table(ram_bag,[{index, [ix]}, {attributes, [key, ix, val]},
+                                                {ram_copies, Nodes}]),
+    {atomic, ok} = mnesia:create_table(do_bag, [{index, [ix]}, {attributes, [key, ix, val]},
+                                                {disc_only_copies, Nodes}]),
+    Test = fun(Tab) ->
+                   io:format("Testing: ~p~n",[Tab]),
+                   Rec = {Tab, 2, 4, data},
+                   Rec2 = {Tab, 3, 5, data},
+                   ok = mnesia:dirty_write(Rec),
+                   ok = mnesia:dirty_write(Rec2),
+                   [Rec] = mnesia:dirty_index_read(Tab, 4, ix),
+                   ?match(ok, mnesia:dirty_delete_object({Tab, 2, 4, does_not_exist})),
+                   [Rec] = mnesia:dirty_read(Tab, 2),
+                   [Rec] = mnesia:dirty_index_read(Tab, 4, ix),
+                   ?match(ok, mnesia:dirty_delete_object(Rec)),
+                   [] = mnesia:dirty_read(Tab, 2),
+                   [] = mnesia:dirty_index_read(Tab, 4, ix),
+                   [Rec2] = mnesia:dirty_read(Tab, 3),
+                   [Rec2] = mnesia:dirty_index_read(Tab, 5, ix)
+           end,
+    [Test(Tab) || Tab <- [ram_set,do_set,ram_bag,do_bag]],
+    ?verify_mnesia(Nodes, []).
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Add and drop indecies
-- 
2.31.1

openSUSE Build Service is sponsored by