723
728
read(Tid, Ts, Tab, Key, LockKind)
724
729
when atom(Tab), Tab /= schema ->
725
case element(1, Tid) of
727
?ets_lookup(Tab, Key);
729
Store = Ts#tidstore.store,
734
mnesia_locker:rlock(Tid, Store, Oid);
736
mnesia_locker:rwlock(Tid, Store, Oid);
738
mnesia_locker:sticky_rwlock(Tid, Store, Oid);
740
abort({bad_type, Tab, LockKind})
742
add_written(?ets_lookup(Store, Oid), Tab, Objs);
730
case element(1, Tid) of
732
?ets_lookup(Tab, Key);
734
Store = Ts#tidstore.store,
739
mnesia_locker:rlock(Tid, Store, Oid);
741
mnesia_locker:rwlock(Tid, Store, Oid);
743
mnesia_locker:sticky_rwlock(Tid, Store, Oid);
745
abort({bad_type, Tab, LockKind})
747
add_written(?ets_lookup(Store, Oid), Tab, Objs);
746
751
read(_Tid, _Ts, Tab, _Key, _LockKind) ->
747
752
abort({bad_type, Tab}).
755
case get(mnesia_activity_state) of
756
{?DEFAULT_ACCESS, Tid, Ts} ->
759
Mod:first(Tid, Ts, Tab);
761
abort(no_transaction)
765
when atom(Tab), Tab /= schema ->
766
case element(1, Tid) of
770
lock_table(Tid, Ts, Tab, read),
772
Key = dirty_first(Tab),
773
stored_keys(Tab,Key,'$end_of_table',Ts,next,
774
val({Tab, setorbag}));
778
first(_Tid, _Ts,Tab) ->
779
abort({bad_type, Tab}).
782
case get(mnesia_activity_state) of
783
{?DEFAULT_ACCESS, Tid, Ts} ->
786
Mod:last(Tid, Ts, Tab);
788
abort(no_transaction)
792
when atom(Tab), Tab /= schema ->
793
case element(1, Tid) of
797
lock_table(Tid, Ts, Tab, read),
799
Key = dirty_last(Tab),
800
stored_keys(Tab,Key,'$end_of_table',Ts,prev,
801
val({Tab, setorbag}));
805
last(_Tid, _Ts,Tab) ->
806
abort({bad_type, Tab}).
809
case get(mnesia_activity_state) of
810
{?DEFAULT_ACCESS,Tid,Ts} ->
811
next(Tid,Ts,Tab,Key);
813
Mod:next(Tid,Ts,Tab,Key);
815
abort(no_transaction)
818
when atom(Tab), Tab /= schema ->
819
case element(1, Tid) of
823
lock_table(Tid, Ts, Tab, read),
825
New = (catch dirty_next(Tab,Key)),
826
stored_keys(Tab,New,Key,Ts,next,
827
val({Tab, setorbag}));
831
next(_Tid, _Ts,Tab,_) ->
832
abort({bad_type, Tab}).
835
case get(mnesia_activity_state) of
836
{?DEFAULT_ACCESS,Tid,Ts} ->
837
prev(Tid,Ts,Tab,Key);
839
Mod:prev(Tid,Ts,Tab,Key);
841
abort(no_transaction)
844
when atom(Tab), Tab /= schema ->
845
case element(1, Tid) of
849
lock_table(Tid, Ts, Tab, read),
851
New = (catch dirty_prev(Tab,Key)),
852
stored_keys(Tab,New,Key,Ts,prev,
853
val({Tab, setorbag}));
857
prev(_Tid, _Ts,Tab,_) ->
858
abort({bad_type, Tab}).
860
%% Compensate for transaction written and/or deleted records
861
stored_keys(Tab,'$end_of_table',Prev,Ts,Op,Type) ->
862
case ts_keys(Ts#tidstore.store,Tab,Op,Type,[]) of
863
[] -> '$end_of_table';
864
Keys when Type == ordered_set->
865
get_ordered_tskey(Prev,Keys,Op);
867
get_next_tskey(Prev,Keys,Tab)
869
stored_keys(Tab,{'EXIT',{aborted,R={badarg,[Tab,Key]}}},
870
Key,#tidstore{store=Store},Op,Type) ->
871
%% Had to match on error, ouch..
872
case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
875
case lists:last(Ops) of
876
[delete] -> abort(R);
878
case ts_keys(Store,Tab,Op,Type,[]) of
879
[] -> '$end_of_table';
880
Keys -> get_next_tskey(Key,Keys,Tab)
884
stored_keys(_,{'EXIT',{aborted,R}},_,_,_,_) ->
886
stored_keys(Tab,Key,Prev,#tidstore{store=Store},Op,ordered_set) ->
887
case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
889
Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]),
890
get_ordered_tskey(Prev,Keys,Op);
892
case lists:last(Ops) of
896
Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]),
897
get_ordered_tskey(Prev,Keys,Op)
900
stored_keys(Tab,Key,_,#tidstore{store=Store},Op,_) ->
901
case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
904
case lists:last(Ops) of
905
[delete] -> mnesia:Op(Tab,Key);
910
get_ordered_tskey('$end_of_table', [First|_],_) -> First;
911
get_ordered_tskey(Prev, [First|_], next) when Prev < First -> First;
912
get_ordered_tskey(Prev, [First|_], prev) when Prev > First -> First;
913
get_ordered_tskey(Prev, [_|R],Op) -> get_ordered_tskey(Prev,R,Op);
914
get_ordered_tskey(_, [],_) -> '$end_of_table'.
916
get_next_tskey(_, [],_) -> '$end_of_table';
917
get_next_tskey(Key,Keys,Tab) ->
919
if Key == '$end_of_table' -> hd(Keys);
921
case lists:dropwhile(fun(A) -> A /= Key end, Keys) of
922
[] -> hd(Keys); %% First stored key
923
[Key] -> '$end_of_table';
924
[Key,Next2|_] -> Next2
928
'$end_of_table' -> '$end_of_table';
929
_ -> %% Really slow anybody got another solution??
930
case dirty_read(Tab, Next) of
933
%% Updated value we already returned this key
934
get_next_tskey(Next,Keys,Tab)
938
ts_keys(Store, Tab, Op, Type, Def) ->
939
All = ?ets_match(Store, {{Tab,'$1'},'_','$2'}),
940
Keys = ts_keys_1(All, Def),
942
Type == ordered_set, Op == prev ->
943
lists:reverse(lists:sort(Keys));
944
Type == ordered_set ->
952
ts_keys_1([[Key, write]|R], []) ->
954
ts_keys_1([[Key, write]|R], Acc=[Key|_]) ->
956
ts_keys_1([[Key, write]|R], Acc) ->
957
ts_keys_1(R, [Key|Acc]);
958
ts_keys_1([[Key, delete]|R], [Key|Acc]) ->
960
ts_keys_1([_|R], Acc) ->
962
ts_keys_1([], Acc) ->
749
966
%%%%%%%%%%%%%%%%%%%%%
773
990
end, RAcc, Stored);
774
991
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
775
992
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
776
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, Stored);
993
{_, Tid, Ts} = get(mnesia_activity_state),
994
do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, Stored);
777
995
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
778
996
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
779
do_foldl(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored);
997
{_, Tid, Ts} = get(mnesia_activity_state),
998
do_foldl(Tid, Ts, Tab, Key, Fun, NewAcc, ordered_set, Stored);
780
999
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
781
1000
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
782
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
1001
{_, Tid, Ts} = get(mnesia_activity_state),
1002
do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
783
1003
do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
784
1004
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
785
1005
NewStored = ordsets:del_element(Key, Stored),
786
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored).
1006
{_, Tid, Ts} = get(mnesia_activity_state),
1007
do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored).
788
1009
foldr(Fun, Acc, Tab) ->
789
1010
foldr(Fun, Acc, Tab, read).
815
1036
end, RAcc, Stored);
816
1037
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
817
1038
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
818
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, Stored);
1039
{_, Tid, Ts} = get(mnesia_activity_state),
1040
do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, Stored);
819
1041
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
820
1042
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
821
do_foldr(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored);
1043
{_, Tid, Ts} = get(mnesia_activity_state),
1044
do_foldr(Tid, Ts, Tab, Key, Fun, NewAcc, ordered_set, Stored);
822
1045
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
823
1046
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
824
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
1047
{_, Tid, Ts} = get(mnesia_activity_state),
1048
do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
825
1049
do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
826
1050
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
827
1051
NewStored = ordsets:del_element(Key, Stored),
828
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, Type, NewStored).
1052
{_, Tid, Ts} = get(mnesia_activity_state),
1053
do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, Type, NewStored).
830
1055
init_iteration(ActivityId, Opaque, Tab, LockKind) ->
831
1056
lock(ActivityId, Opaque, {table, Tab}, LockKind),
980
1205
add_ordered_match([], Objs, Acc) ->
981
1206
lists:reverse(Acc, Objs).
1209
add_sel_match(Sorted, Objs, ordered_set) ->
1210
add_sel_ordered_match(Sorted, Objs, []);
1211
add_sel_match(Written, Objs, Type) ->
1212
add_sel_match(Written, Objs, Type, []).
1214
add_sel_match([], Objs, _Type, Acc) ->
1215
{Objs,lists:reverse(Acc)};
1216
add_sel_match([Op={Oid, _, delete}|R], Objs, Type, Acc) ->
1217
case deloid(Oid, Objs) of
1219
add_sel_match(R, Objs, Type, [Op|Acc]);
1220
NewObjs when Type == set ->
1221
add_sel_match(R, NewObjs, Type, Acc);
1222
NewObjs -> %% If bag we may get more in next chunk
1223
add_sel_match(R, NewObjs, Type, [Op|Acc])
1225
add_sel_match([Op = {_Oid, Val, delete_object}|R], Objs, Type, Acc) ->
1226
case lists:delete(Val, Objs) of
1228
add_sel_match(R, Objs, Type, [Op|Acc]);
1229
NewObjs when Type == set ->
1230
add_sel_match(R, NewObjs, Type, Acc);
1232
add_sel_match(R, NewObjs, Type, [Op|Acc])
1234
add_sel_match([Op={Oid={_,Key}, Val, write}|R], Objs, bag, Acc) ->
1235
case lists:keymember(Key, 2, Objs) of
1237
add_sel_match(R,[Val|lists:delete(Val,Objs)],bag,
1238
[{Oid,Val,delete_object}|Acc]);
1240
add_sel_match(R,Objs,bag,[Op|Acc])
1242
add_sel_match([Op={Oid, Val, write}|R], Objs, set, Acc) ->
1243
case deloid(Oid,Objs) of
1245
add_sel_match(R, Objs,set, [Op|Acc]);
1247
add_sel_match(R, [Val | NewObjs],set, Acc)
1250
%% For ordered_set only !!
1251
add_sel_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs],Acc)
1252
when Key > element(2, Obj) ->
1253
add_sel_ordered_match(Written, Objs, [Obj|Acc]);
1254
add_sel_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_],Acc)
1255
when Key < element(2, Obj) ->
1256
add_sel_ordered_match(Rest,[Val|Objs],Acc);
1257
add_sel_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc)
1258
when Key < element(2, Obj) ->
1259
add_sel_ordered_match(Rest,Objs,Acc);
1260
%% Greater than last object
1261
add_sel_ordered_match(Ops1, [], Acc) ->
1262
{lists:reverse(Acc), Ops1};
1263
%% Keys are equal from here
1264
add_sel_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) ->
1265
add_sel_ordered_match(Rest, [Val|Objs], Acc);
1266
add_sel_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) ->
1267
add_sel_ordered_match(Rest, Objs, Acc);
1268
add_sel_ordered_match([{_, Val, delete_object}|Rest], [Val|Objs], Acc) ->
1269
add_sel_ordered_match(Rest, Objs, Acc);
1270
add_sel_ordered_match([{_, _, delete_object}|Rest], Objs, Acc) ->
1271
add_sel_ordered_match(Rest, Objs, Acc);
1272
add_sel_ordered_match([], Objs, Acc) ->
1273
{lists:reverse(Acc, Objs),[]}.
1278
deloid({Tab, Key}, [H | T]) when element(2, H) == Key ->
1279
deloid({Tab, Key}, T);
1280
deloid(Oid, [H | T]) ->
1281
[H | deloid(Oid, T)].
984
1283
%%%%%%%%%%%%%%%%%%
1034
1323
TabRecs = SelectFun(FixedSpec),
1035
1324
FixedRes = add_match(Written, TabRecs, Type),
1036
1325
CMS = ets:match_spec_compile(Spec),
1039
% ets:match_spec_run(lists:sort(FixedRes), CMS);
1041
% ets:match_spec_run(FixedRes, CMS)
1043
1326
ets:match_spec_run(FixedRes, CMS)
1046
1329
SelectFun(Spec)
1049
get_record_pattern([]) ->
1332
select_lock(Tid,Ts,LockKind,Spec,Tab) ->
1333
%% Avoid table lock if possible
1335
[{HeadPat,_, _}] when tuple(HeadPat), size(HeadPat) > 2 ->
1336
Key = element(2, HeadPat),
1337
case has_var(Key) of
1338
false -> lock_record(Tid, Ts, Tab, Key, LockKind);
1339
true -> lock_table(Tid, Ts, Tab, LockKind)
1342
lock_table(Tid, Ts, Tab, LockKind)
1346
select(Tab, Pat, NObjects, LockKind)
1347
when atom(Tab), Tab /= schema, list(Pat), number(NObjects) ->
1348
case get(mnesia_activity_state) of
1349
{?DEFAULT_ACCESS, Tid, Ts} ->
1350
select(Tid, Ts, Tab, Pat, NObjects, LockKind);
1352
Mod:select(Tid, Ts, Tab, Pat, NObjects, LockKind);
1354
abort(no_transaction)
1356
select(Tab, Pat, NObjects, _Lock) ->
1357
abort({badarg, Tab, Pat, NObjects}).
1359
select(Tid, Ts, Tab, Spec, NObjects, LockKind) ->
1360
Where = val({Tab,where_to_read}),
1361
Type = mnesia_lib:storage_type_at_node(Where,Tab),
1362
InitFun = fun(FixedSpec) -> dirty_sel_init(Where,Tab,FixedSpec,NObjects,Type) end,
1363
fun_select(Tid,Ts,Tab,Spec,LockKind,Tab,InitFun,NObjects,Where,Type).
1365
-record(mnesia_select, {tab,tid,node,storage,cont,written=[],spec,type,orig}).
1367
fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, Init, NObjects, Node, Storage) ->
1368
Def = #mnesia_select{tid=Tid,node=Node,storage=Storage,tab=Tab,orig=Spec},
1369
case element(1, Tid) of
1371
select_state(mnesia_lib:db_select_init(ram_copies,Tab,Spec,NObjects),Def);
1373
select_lock(Tid,Ts,LockKind,Spec,Tab),
1374
Store = Ts#tidstore.store,
1375
do_fixtable(Tab, Store),
1377
Written0 = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}),
1380
%% Nothing changed in the table during this transaction,
1381
%% Simple case get results from [d]ets
1382
select_state(Init(Spec),Def);
1384
%% Hard (slow case) records added or deleted earlier
1385
%% in the transaction, have to cope with that.
1386
Type = val({Tab, setorbag}),
1388
if Type == ordered_set -> %% Sort stable
1389
lists:keysort(1,Written0);
1393
FixedSpec = get_record_pattern(Spec),
1394
CMS = ets:match_spec_compile(Spec),
1395
trans_select(Init(FixedSpec),
1396
Def#mnesia_select{written=Written,spec=CMS,type=Type})
1399
select_state(Init(Spec),Def)
1403
case get(mnesia_activity_state) of
1404
{?DEFAULT_ACCESS, Tid, Ts} ->
1405
select_cont(Tid,Ts,Cont);
1407
Mod:select_cont(Tid,Ts,Cont);
1409
abort(no_transaction)
1412
select_cont(_Tid,_Ts,'$end_of_table') ->
1414
select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid,cont=Cont, orig=Ms})
1415
when element(1,Tid) == ets ->
1417
'$end_of_table' -> '$end_of_table';
1418
_ -> select_state(mnesia_lib:db_select_cont(ram_copies,Cont,Ms),State)
1420
select_cont(Tid,_,State=#mnesia_select{tid=Tid,written=[]}) ->
1421
select_state(dirty_sel_cont(State),State);
1422
select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid}) ->
1423
trans_select(dirty_sel_cont(State), State);
1424
select_cont(_Tid2,_,#mnesia_select{tid=_Tid1}) -> % Missmatching tids
1425
abort(wrong_transaction);
1426
select_cont(_,_,Cont) ->
1427
abort({badarg, Cont}).
1429
trans_select('$end_of_table', #mnesia_select{written=Written0,spec=CMS,type=Type}) ->
1430
Written = add_match(Written0, [], Type),
1431
{ets:match_spec_run(Written, CMS), '$end_of_table'};
1432
trans_select({TabRecs,Cont}, State = #mnesia_select{written=Written0,spec=CMS,type=Type}) ->
1433
{FixedRes,Written} = add_sel_match(Written0, TabRecs, Type),
1434
select_state({ets:match_spec_run(FixedRes, CMS),Cont},
1435
State#mnesia_select{written=Written}).
1437
select_state({Matches, Cont}, MS) ->
1438
{Matches, MS#mnesia_select{cont=Cont}};
1439
select_state('$end_of_table',_) -> '$end_of_table'.
1441
get_record_pattern([]) -> [];
1051
1442
get_record_pattern([{M,C,_B}|R]) ->
1052
1443
[{M,C,['$_']} | get_record_pattern(R)].
1056
deloid({Tab, Key}, [H | T]) when element(2, H) == Key ->
1057
deloid({Tab, Key}, T);
1058
deloid(Oid, [H | T]) ->
1059
[H | deloid(Oid, T)].
1061
1445
all_keys(Tab) ->
1062
1446
case get(mnesia_activity_state) of
1063
1447
{?DEFAULT_ACCESS, Tid, Ts} ->
2180
2570
mnesia_text:dump_to_textfile(F).
2182
2572
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578
{[Trav,Lock,NObjects],QlcOptions0} =
2579
qlc_opts(Opts,[{traverse,select},{lock,read},{n_objects,100}]),
2582
fun() -> qlc_select(select(Tab,Ms,NObjects,Lock)) end;
2584
fun(Ms) -> qlc_select(select(Tab,Ms,NObjects,Lock)) end;
2586
erlang:fault({badarg, {Trav,[Tab, Opts]}})
2588
Pre = fun(Arg) -> pre_qlc(Arg, Tab) end,
2589
Post = fun() -> post_qlc(Tab) end,
2590
Info = fun(Tag) -> qlc_info(Tab, Tag) end,
2591
ParentFun = fun() ->
2592
{mnesia_activity, mnesia:get_activity_id()}
2598
LFun = fun(2, Keys) ->
2599
Read = fun(Key) -> read(Tab,Key,Lock) end,
2600
lists:flatmap(Read, Keys);
2602
IdxRead = fun(Key) -> index_read(Tab,Key,Index) end,
2603
lists:flatmap(IdxRead, Keys)
2605
[{lookup_fun, LFun}]
2607
MFA = fun(Type) -> qlc_format(Type, Tab, NObjects, Lock, Opts) end,
2608
QlcOptions = [{pre_fun, Pre}, {post_fun, Post},
2609
{info_fun, Info}, {parent_fun, ParentFun},
2610
{format_fun, MFA}|Lookup] ++ QlcOptions0,
2611
qlc:table(TF, QlcOptions).
2613
pre_qlc(Opts, Tab) ->
2615
case get(mnesia_activity_state) of
2617
case lists:keysearch(parent_value, 1, Opts) of
2618
{value, {parent_value,{mnesia_activity,undefined}}} ->
2619
abort(no_transaction);
2620
{value, {parent_value,{mnesia_activity,Aid}}} ->
2621
{value,{stop_fun,Stop}} =
2622
lists:keysearch(stop_fun,1,Opts),
2623
put_activity_id(Aid,Stop),
2626
abort(no_transaction)
2631
case element(1,Tid) of
2634
case ?catch_val({Tab, setorbag}) of
2637
dirty_rpc(Tab, mnesia_tm, fixtable, [Tab,true,self()]),
2643
case catch get(mnesia_activity_state) of
2646
case ?catch_val({Tab, setorbag}) of
2650
dirty_rpc(Tab, mnesia_tm, fixtable, [Tab,false,self()]),
2655
qlc_select('$end_of_table') -> [];
2656
qlc_select({Objects, Cont}) ->
2657
Objects ++ fun() -> qlc_select(select(Cont)) end.
2659
qlc_opts(Opts, Keys) when is_list(Opts) ->
2660
qlc_opts(Opts, Keys, []);
2661
qlc_opts(Option, Keys) ->
2662
qlc_opts([Option], Keys, []).
2664
qlc_opts(Opts, [{Key,Def}|Keys], Acc) ->
2665
Opt = case lists:keysearch(Key,1, Opts) of
2666
{value, {Key,Value}} ->
2671
qlc_opts(lists:keydelete(Key,1,Opts),Keys,[Opt|Acc]);
2672
qlc_opts(Opts,[],Acc) -> {lists:reverse(Acc),Opts}.
2674
qlc_info(Tab, num_of_objects) ->
2675
dirty_rpc(Tab, ?MODULE, raw_table_info, [Tab, size]);
2676
qlc_info(_, keypos) -> 2;
2677
qlc_info(_, is_unique_objects) -> true;
2678
qlc_info(Tab, is_unique_keys) ->
2679
case val({Tab, type}) of
2681
ordered_set -> true;
2684
qlc_info(Tab, is_sorted_objects) ->
2685
case val({Tab, type}) of
2687
case ?catch_val({Tab, frag_hash}) of
2690
_ -> %% Fragmented tables are not ordered
2695
qlc_info(Tab, indices) ->
2697
qlc_info(_Tab, _) ->
2700
qlc_format(all, Tab, NObjects, Lock, Opts) ->
2701
{?MODULE, table, [Tab,[{n_objects, NObjects}, {lock,Lock}|Opts]]};
2702
qlc_format({match_spec, Ms}, Tab, NObjects, Lock, Opts) ->
2703
{?MODULE, table, [Tab,[{traverse,{select,Ms}},{n_objects, NObjects}, {lock,Lock}|Opts]]};
2704
qlc_format({lookup, 2, Keys}, Tab, _, Lock, _) ->
2705
io_lib:format("lists:flatmap(fun(V) -> "
2706
"~w:read(~w, V, ~w) end, ~w)",
2707
[?MODULE, Tab, Lock, Keys]);
2708
qlc_format({lookup, Index,Keys}, Tab, _, _, _) ->
2709
io_lib:format("lists:flatmap(fun(V) -> "
2710
"~w:index_read(~w, V, ~w) end, ~w)",
2711
[?MODULE, Tab, Index, Keys]).
2714
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716
do_fixtable(Tab, #tidstore{store=Store}) ->
2717
do_fixtable(Tab,Store);
2718
do_fixtable(Tab, Store) ->
2719
case ?catch_val({Tab, setorbag}) of
2723
case ?ets_match_object(Store, {fixtable, {Tab, '_'}}) of
2725
Node = dirty_rpc(Tab, mnesia_tm, fixtable, [Tab,true,self()]),
2726
?ets_insert(Store, {fixtable, {Tab, Node}});
2733
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2183
2734
%% Mnemosyne exclusive
2185
2736
get_activity_id() ->