%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(mnesia_index_plugin_test).
-author('[email protected]').
-export([init_per_testcase/2, end_per_testcase/2,
init_per_group/2, end_per_group/2,
init_per_suite/1, end_per_suite/1,
all/0, groups/0]).
-export([
add_rm_plugin/1,
tab_with_plugin_index/1,
tab_with_multiple_plugin_indexes/1,
ix_match_w_plugin/1,
ix_match_w_plugin_ordered/1,
ix_match_w_plugin_bag/1
]).
-export([ix_prefixes/3, % test plugin
ix_prefixes2/3]). % test plugin 2
-include("mnesia_test_lib.hrl").
init_per_suite(Conf) ->
Conf.
end_per_suite(Conf) ->
Conf.
init_per_testcase(Func, Conf) ->
mnesia_test_lib:init_per_testcase(Func, Conf).
end_per_testcase(Func, Conf) ->
mnesia_test_lib:end_per_testcase(Func, Conf).
all() ->
[add_rm_plugin,
tab_with_plugin_index,
tab_with_multiple_plugin_indexes,
ix_match_w_plugin,
ix_match_w_plugin_ordered,
ix_match_w_plugin_bag].
groups() ->
[].
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
add_rm_plugin(suite) -> [];
add_rm_plugin(Config) when is_list(Config) ->
[N1, N2] = Nodes = ?acquire_nodes(2, Config),
ok = add_plugin(),
ok = rpc_check_plugin(N1),
ok = rpc_check_plugin(N2),
ok = add_plugin2(),
ok = del_plugin(),
ok = del_plugin2(),
ok = add_plugin(),
ok = add_plugin2(),
ok = del_plugin(),
ok = del_plugin2(),
?verify_mnesia(Nodes, []).
-define(PLUGIN1, {{pfx},?MODULE,ix_prefixes}).
-define(PLUGIN2, {{pfx2},?MODULE,ix_prefixes2}).
add_plugin() ->
{atomic, ok} = mnesia_schema:add_index_plugin({pfx}, ?MODULE, ix_prefixes),
[?PLUGIN1] = mnesia_schema:index_plugins(),
ok.
add_plugin2() ->
{atomic, ok} = mnesia_schema:add_index_plugin({pfx2}, ?MODULE, ix_prefixes2),
[?PLUGIN1, ?PLUGIN2] = lists:sort(mnesia_schema:index_plugins()),
ok.
del_plugin() ->
{atomic, ok} = mnesia_schema:delete_index_plugin({pfx}),
[?PLUGIN2] = mnesia_schema:index_plugins(),
ok.
del_plugin2() ->
{atomic, ok} = mnesia_schema:delete_index_plugin({pfx2}),
[] = mnesia_schema:index_plugins(),
ok.
rpc_check_plugin(N) ->
[?PLUGIN1] =
rpc:call(N, mnesia_schema, index_plugins, []),
ok.
tab_with_plugin_index(suite) -> [];
tab_with_plugin_index(Config) when is_list(Config) ->
[_N1] = Nodes = ?acquire_nodes(1, Config),
ok = add_plugin(),
{atomic, ok} = mnesia:create_table(t, [{attributes, [k,v1,v2]},
{index, [{{pfx}, ordered},
{v1, ordered},
v2]}]),
[ok,ok,ok,ok] =
[mnesia:dirty_write({t, K, V1, V2})
|| {K,V1,V2} <- [{1,a,"123"},
{2,b,"12345"},
{3,c,"6789"},
{4,d,nil}]],
[{t,1,a,"123"},{t,2,b,"12345"}] =
mnesia:dirty_index_read(t,<<"123">>,{pfx}),
[{t,3,c,"6789"}] =
mnesia:dirty_index_read(t,"6789",v2),
[{t,1,a,"123"}] =
mnesia:dirty_match_object({t,'_',a,"123"}),
[{t,1,a,"123"}] =
mnesia:dirty_select(t, [{ {t,'_',a,"123"}, [], ['$_']}]),
mnesia:dirty_delete(t,2),
[{t,1,a,"123"}] =
mnesia:dirty_index_read(t,<<"123">>,{pfx}),
?verify_mnesia(Nodes, []).
tab_with_multiple_plugin_indexes(suite) -> [];
tab_with_multiple_plugin_indexes(Config) when is_list(Config) ->
[_N1] = Nodes = ?acquire_nodes(1, Config),
ok = add_plugin(),
ok = add_plugin2(),
{atomic, ok} =
mnesia:create_table(u, [{attributes, [k,v1,v2]},
{index, [{{pfx}, ordered},
{{pfx2}, ordered}]}]),
[ok,ok,ok,ok] =
[mnesia:dirty_write({u, K, V1, V2})
|| {K,V1,V2} <- [{1,a,"123"},
{2,b,"12345"},
{3,c,"6789"},
{4,d,nil}]],
[{u,1,a,"123"},{u,2,b,"12345"}] =
mnesia:dirty_index_read(u,<<"123">>,{pfx}),
[{u,1,a,"123"},{u,2,b,"12345"}] =
mnesia:dirty_index_read(u,<<"321">>,{pfx2}),
?verify_mnesia(Nodes, []).
ix_match_w_plugin(suite) -> [];
ix_match_w_plugin(Config) when is_list(Config) ->
[_N1] = Nodes = ?acquire_nodes(1, Config),
ok = add_plugin(),
{atomic, ok} = mnesia:create_table(im1, [{attributes, [k, v1, v2]},
{index, [{{pfx}, ordered},
{v1, ordered}]}]),
fill_and_test_index_match(im1, set),
?verify_mnesia(Nodes, []).
ix_match_w_plugin_ordered(suite) -> [];
ix_match_w_plugin_ordered(Config) when is_list(Config) ->
[_N1] = Nodes = ?acquire_nodes(1, Config),
ok = add_plugin(),
{atomic, ok} = mnesia:create_table(im2, [{attributes, [k, v1, v2]},
{type, ordered_set},
{index, [{{pfx}, ordered},
{v1, ordered}]}]),
fill_and_test_index_match(im2, ordered_set),
?verify_mnesia(Nodes, []).
ix_match_w_plugin_bag(suite) -> [];
ix_match_w_plugin_bag(Config) when is_list(Config) ->
[_N1] = Nodes = ?acquire_nodes(1, Config),
ok = add_plugin(),
{atomic, ok} = mnesia:create_table(im3, [{attributes, [k, v1, v2]},
{type, bag},
{index, [{{pfx}, ordered},
{v1, ordered}]}]),
fill_and_test_index_match(im3, bag),
?verify_mnesia(Nodes, []).
fill_and_test_index_match(Tab, Type) ->
[ok,ok,ok,ok,ok,ok,ok,ok,ok] =
[mnesia:dirty_write({Tab, K, V1, V2})
|| {K,V1,V2} <- [{1,a,"123"},
{2,b,"12345"},
{3,c,"123"},
{4,d,nil},
{5,e,nil},
{6,f,nil},
{7,g,nil}, %% overwritten if not bag
{7,g,"234"},
{8,h,"123"}]],
mnesia:activity(
transaction,
fun() ->
ok = mnesia:write({Tab, 1, aa, "1234"}), %% replaces if not bag
ok = mnesia:delete({Tab, 2}),
ok = mnesia:delete({Tab, 4}),
ok = mnesia:write({Tab, 6, ff, nil}),
ok = mnesia:write({Tab, 7, gg, "123"}),
ok = mnesia:write({Tab, 100, x, nil}),
ok = mnesia:delete_object({Tab,3,c,"123"}),
ok = mnesia:delete_object({Tab,5,e,nil}),
Res = mnesia:index_read(Tab, <<"123">>, {pfx}),
SetRes = [{Tab,1,aa,"1234"}, {Tab,7,gg,"123"}, {Tab,8,h,"123"}],
case Type of
set ->
SetRes = lists:sort(Res);
ordered_set ->
SetRes = Res;
bag ->
[{Tab,1,a,"123"}, {Tab,1,aa,"1234"},
{Tab,7,gg,"123"}, {Tab,8,h,"123"}] = lists:sort(Res)
end
end).
%% ============================================================
%%
ix_prefixes(_Tab, _Pos, Obj) ->
lists:foldl(
fun(V, Acc) when is_list(V) ->
try Pfxs = prefixes(list_to_binary(V)),
Pfxs ++ Acc
catch
error:_ ->
Acc
end;
(V, Acc) when is_binary(V) ->
Pfxs = prefixes(V),
Pfxs ++ Acc;
(_, Acc) ->
Acc
end, [], tl(tuple_to_list(Obj))).
ix_prefixes2(Tab, Pos, Obj) ->
[rev(P) || P <- ix_prefixes(Tab, Pos, Obj)].
rev(B) when is_binary(B) ->
list_to_binary(lists:reverse(binary_to_list(B))).
prefixes(<<P:3/binary, _/binary>>) ->
[P];
prefixes(_) ->
[].