qlc.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,743 行 · 第 1/5 页
ERL
1,743 行
{list, le_info(L), MS}.qual_info([?qual_data(_QNum, _GoI, ?SKIP, fil) | Qdata], Code) -> %% see skip_lookup_filters() [skip | qual_info(Qdata, Code)];qual_info([?qual_data(QNum, _GoI, _SI, fil) | Qdata], Code) -> [element(QNum + 1, Code) | qual_info(Qdata, Code)];qual_info([?qual_data(_QNum, _GoI, _SI, {gen,#join{}}) | Qdata], Code) -> [skip | qual_info(Qdata, Code)];qual_info([?qual_data(QNum, _GoI, _SI, {gen,LE}) | Qdata], Code) -> [{generate,element(QNum + 1, Code),le_info(LE)} | qual_info(Qdata, Code)];qual_info([], _Code) -> [].join_info(Join, QInfo, Qdata, Code) -> #qlc_join{kind = Kind, q1 = QNum1a, c1 = C1, q2 = QNum2a, c2 = C2, opt = Opt} = Join, {?qual_data(JQNum,_,_,_), Rev, QNum1, QNum2, _WH1, _WH2, CsFun} = find_join_data(Qdata, QNum1a, QNum2a), {Cs1, Cs2, _Compat} = CsFun(), L = 0, G1_0 = {var,L,'G1'}, G2_0 = {var,L,'G2'}, JP = element(JQNum + 1, Code), %% Create code for wh1 and wh2 in #join{}: {{I1,G1}, {I2,G2}, QInfoL} = if Kind =:= merge -> %% Create code for wh1 and wh2 in #join{}: {JG1,QInfo1} = join_merge_info(QNum1, QInfo, Code, G1_0, Cs1), {JG2,QInfo2} = join_merge_info(QNum2, QInfo, Code, G2_0, Cs2), {JG1, JG2, QInfo1 ++ QInfo2}; Rev -> {JG2,QInfo2} = join_merge_info(QNum2, QInfo, Code, G2_0, Cs2), {J1, QInfo1} = join_lookup_info(QNum1, QInfo, G1_0), {{J1,G1_0}, JG2, QInfo2 ++ [QInfo1]}; true -> {JG1,QInfo1} = join_merge_info(QNum1, QInfo, Code, G1_0, Cs1), {J2, QInfo2} = join_lookup_info(QNum2, QInfo, G2_0), {JG1, {J2,G2_0}, QInfo1 ++ [QInfo2]} end, {JOptVal, JOp} = case Kind of merge -> {merge, '=='}; {lookup, _} -> {lookup, '=:='} end, JOpt = [{join, JOptVal}] ++ opt_info(join_unique_cache(Opt)), JFil = term_to_binary({op,L,JOp, {call,L,{atom,L,element},[{integer,L,C1},G1]}, {call,L,{atom,L,element},[{integer,L,C2},G2]}}), P = term_to_binary({cons, L, G1, G2}), JInfo = {generate, JP, {qlc, P, QInfoL ++ [JFil], JOpt}}, {Before, [I1 | After]} = lists:split(QNum1 - 1, QInfo), Before ++ [JInfo] ++ lists:delete(I2, After).%% qlc:q(P0 || P0 = Pattern <- H1, ConstFilters), %% where "P0" is a fresh variable and ConstFilters are filters that%% test constant values of pattern columns.join_merge_info(QNum, QInfo, Code, G, ExtraConstants) -> {generate, _, LEInfo}=I = lists:nth(QNum, QInfo), P = binary_to_term(element(QNum + 1, Code)), case {P, ExtraConstants} of {{var, _, _}, []} -> %% No need to introduce a QLC expression. {{I,P}, [I]}; _ -> {EPV, M} = case P of {var, _, _} -> %% No need to introduce a pattern variable. {P, P}; _ -> {PV, _} = qlc_pt:aux_name1('P', 0, vars(P)), L = 0, V = {var, L, PV}, {V, {match, L, V, P}} end, DQP = term_to_binary(EPV), LEI = {generate, term_to_binary(M), LEInfo}, TP = term_to_binary(G), CFs = [begin Call = {call,0,{atom,0,element},[{integer,0,Col},EPV]}, F = list2op([{op,0,'=:=',erl_parse:abstract(Con),Call} || Con <- Cs], 'or'), term_to_binary(F) end || {Col,Cs} <- ExtraConstants], {{I,G}, [{generate, TP, {qlc, DQP, [LEI | CFs], []}}]} end.list2op([E], _Op) -> E;list2op([E | Es], Op) -> {op,0,Op,E,list2op(Es, Op)}.join_lookup_info(QNum, QInfo, G) -> {generate, _, LEInfo}=I = lists:nth(QNum, QInfo), TP = term_to_binary(G), {I, {generate, TP, LEInfo}}.opt_info(#optz{unique = Unique, cache = Cache0, join_option = JoinOption}) -> %% No 'nested_loop' options are added here, even if there are %% nested loops to carry out, unless a 'nested_loop' was given as %% option. The reason is that QLC does not know about all %% instances of nested loops. Cache = if Cache0 -> ets; true -> Cache0 end, [{T,V} || {T,V} <- [{cache,Cache},{unique,Unique}], V =/= default_option(T)] ++ [{T,V} || {T,V} <- [{join,JoinOption}], V =:= nested_loop].prepare_qlc(H, InitialValue, GUnique, GCache, TmpDir, MaxList) -> GOpt = #qlc_opt{unique = GUnique, cache = GCache, tmpdir = TmpDir, max_list = MaxList}, case opt_le(prep_le(H, GOpt), 1) of #prepared{qh = #qlc{} = QLC}=Prep -> Prep#prepared{qh = QLC#qlc{init_value = InitialValue}}; #prepared{qh = #simple_qlc{}=SimpleQLC}=Prep -> Prep#prepared{qh = SimpleQLC#simple_qlc{init_value = InitialValue}}; Prep -> Prep end.%%% The options given to append, q and table (unique and cache) as well%%% as the type of expression (list, table, append, qlc...) are%%% analyzed by prep_le. The results are is_unique_objects and%%% is_cached. List expressions are evaluated. prep_le(#qlc_lc{lc = LC_fun, opt = #qlc_opt{} = Opt0}=H, GOpt) -> #qlc_opt{unique = GUnique, cache = GCache, tmpdir = TmpDir, max_list = MaxList} = GOpt, Unique = Opt0#qlc_opt.unique or GUnique, Cache = if not GCache -> Opt0#qlc_opt.cache; true -> GCache end, Opt = Opt0#qlc_opt{unique = Unique, cache = Cache, tmpdir = TmpDir, max_list = MaxList}, prep_qlc_lc(LC_fun(), Opt, GOpt, H);prep_le(#qlc_table{info_fun = IF}=T, GOpt) -> {SortInfo, Sorted} = table_sort_info(T), IsUnique = grd(IF, is_unique_objects), Prep = #prepared{qh = T, sort_info = SortInfo, sorted = Sorted, is_unique_objects = IsUnique}, Opt = if IsUnique or not GOpt#qlc_opt.unique, T#qlc_table.ms =:= no_match_spec -> GOpt#qlc_opt{cache = false}; true -> GOpt end, may_create_simple(Opt, Prep);prep_le(#qlc_append{hl = HL}, GOpt) -> case lists:flatmap(fun(#prepared{qh = #qlc_list{l = []}}) -> []; (#prepared{qh = #qlc_append{hl = HL1}}) -> HL1; (H) -> [H] end, [prep_le(H, GOpt) || H <- HL]) of []=Nil -> short_list(Nil); [Prep] -> Prep; PrepL -> Cache = lists:all(fun(#prepared{is_cached = IM}) -> IM =/= false end, PrepL), %% The handles in hl are replaced by prepared handles: Prep = #prepared{qh = #qlc_append{hl = PrepL}, is_cached = Cache}, may_create_simple(GOpt, Prep) end;prep_le(#qlc_sort{h = H0}=Q0, GOpt) -> %% The handle h is replaced by a prepared handle: Q = Q0#qlc_sort{h = prep_le(H0, GOpt)}, prep_sort(Q, GOpt);prep_le([_, _ | _]=L, GOpt) -> Prep = #prepared{qh = #qlc_list{l = L}, is_cached = true}, Opt = if not GOpt#qlc_opt.unique -> GOpt#qlc_opt{cache = false}; true -> GOpt end, may_create_simple(Opt, Prep);prep_le(L, _GOpt) when is_list(L) -> short_list(L);prep_le(T, _GOpt) -> erlang:error({unsupported_qlc_handle, #qlc_handle{h = T}}).eval_le(LE_fun, GOpt) -> case LE_fun() of {error, ?MODULE, _} = Error -> throw_error(Error); R -> case get_handle(R) of badarg -> erlang:error(badarg, [R]); H -> prep_le(H, GOpt) end end.prep_qlc_lc({simple_v1, PVar, LE_fun, L}, Opt, GOpt, _H) -> check_lookup_option(Opt, false), prep_simple_qlc(PVar, L, eval_le(LE_fun, GOpt), Opt);prep_qlc_lc({single_v1, QFun, CodeF, Qdata0, _, MS, PosFun}, Opt, GOpt, _H) -> %% R10B check_join_option(Opt), %% Filter optional: [?qual_data(QNum, GoI_G, SI_G, {gen, LE_fun}) | Filter] = Qdata0, Prep0 = eval_le(LE_fun, GOpt), Fs = [0], % (effect: the match specification is always run) {Done, _Skip, LookUp, Prep} = prep_gen(Prep0, PosFun, {MS,Fs}, Opt), check_lookup_option(Opt, LookUp), if Done =:= replace -> Prep; true -> Qdata = [?qual_data(QNum, GoI_G, SI_G, {gen, Prep}) | Filter], QOpt = undefined, prep_qlc(QFun, CodeF, Qdata, QOpt, Opt) end;prep_qlc_lc({qlc_v1, QFun, CodeF, Qdata0, QOpt}, Opt, GOpt, _H) -> F = fun(?qual_data(_QNum, _GoI, _SI, fil)=QualData, ModGens) -> {QualData, ModGens}; (?qual_data(_QNum, _GoI, _SI, {gen, #join{}})=QualData, ModGens) -> {QualData, ModGens}; (?qual_data(QNum, GoI, SI, {gen, LE_fun}), ModGens0) -> Prep1 = eval_le(LE_fun, GOpt), {Prep, ModGens} = prep_generator(QNum, Prep1, QOpt, Opt, ModGens0), {?qual_data(QNum, GoI, SI, {gen, Prep}), ModGens} end, {Qdata, ModGens} = lists:mapfoldl(F, [], Qdata0), SomeLookUp = lists:keysearch(true, 2, ModGens) =/= false, check_lookup_option(Opt, SomeLookUp), case ModGens of [{_QNum, _LookUp, all, OnePrep}] -> check_join_option(Opt), OnePrep; _ -> Prep0 = prep_qlc(QFun, CodeF, Qdata, QOpt, Opt), SkipFs = lists:flatmap(fun({_QNum,_LookUp,Fs,_Prep}) -> Fs end, ModGens), Prep1 = skip_lookup_filters(Prep0, SkipFs), prep_join(Prep1, QOpt, Opt) end;prep_qlc_lc(_, _Opt, _GOpt, H) -> erlang:error({unsupported_qlc_handle, #qlc_handle{h = H}}).prep_generator(QNum, Prep0, QOpt, Opt, ModGens) -> PosFun = constants(QOpt, QNum), MSFs = case match_specs(QOpt, QNum) of undefined -> {no_match_spec, []}; {_, _}=MSFs0 -> MSFs0 end, case prep_gen(Prep0, PosFun, MSFs, Opt) of {replace, Fs, LookUp, Prep} -> {Prep, [{QNum,LookUp,Fs,Prep} | ModGens]}; {skip, SkipFils, LookUp, Prep} -> {Prep, [{QNum,LookUp,SkipFils,Prep} | ModGens]}; {no, _Fs, _LookUp, Prep} -> {Prep, ModGens} end.prep_gen(#prepared{qh = LE0}=Prep0, PosFun, {MS, Fs}, Opt) -> {LuV, {STag,SkipFils}} = find_const_positions(LE0, PosFun, Opt), LU = LuV =/= false, case LE0 of #qlc_table{lu_vals = LuV0, ms = MS0} when LuV0 =/= undefined; MS0 =/= no_match_spec -> {no, [], false, Prep0}; #qlc_table{} when MS =/= no_match_spec, LU -> MS1 = if Fs =:= SkipFils; STag =:= Fs -> %% The guard of the match specification %% is covered by the lookup. case MS of [{'$1',_Guard,['$1']}] -> % no transformation no_match_spec; [{Head,_Guard,Body}] -> [{Head,[],Body}] % true guard end; true -> MS end, Prep = Prep0#prepared{qh = LE0#qlc_table{lu_vals = LuV,ms = MS1}}, {replace, Fs, LU, Prep}; #qlc_table{} when LU -> Prep = Prep0#prepared{qh = LE0#qlc_table{lu_vals = LuV}}, {skip, SkipFils, LU, Prep}; #qlc_table{trav_MS = true} when MS =/= no_match_spec -> Prep = Prep0#prepared{qh = LE0#qlc_table{ms = MS}}, {replace, Fs, false, may_create_simple(Opt, Prep)}; #qlc_list{l = []} -> % unique and cached {replace, Fs, false, Prep0}; #qlc_list{ms = no_match_spec} when MS =/= no_match_spec -> Prep = Prep0#prepared{qh = LE0#qlc_list{ms = MS}, is_cached = false}, {replace, Fs, false, may_create_simple(Opt, Prep)}; #qlc_list{} when MS =/= no_match_spec -> ListMS = #qlc_list{l = Prep0, ms = MS}, LE = #prepared{qh = ListMS, is_cached = false}, {replace, Fs, false, may_create_simple(Opt, LE)}; _ -> {no, [], false, Prep0} end.-define(SIMPLE_QVAR, 'SQV').may_create_simple(#qlc_opt{unique = Unique, cache = Cache} = Opt, #prepared{is_cached = IsCached, is_unique_objects = IsUnique} = Prep) -> if Unique and not IsUnique; (Cache =/= false) and not IsCached -> prep_simple_qlc(?SIMPLE_QVAR, 1, Prep, Opt); true -> Prep end.%% Sorted. Var kommer den ifr錸? P鍁erkas den av unique&cache=list?prep_simple_qlc(PVar, Line, LE, Opt) -> check_join_option(Opt), #prepared{is_cached = IsCached, sort_info = SortInfo, sorted = Sorted, is_unique_objects = IsUnique} = LE, #qlc_opt{unique = Unique, cache = Cache} = Opt, Cachez = if Unique -> Cache; not IsCached -> Cache; true -> false end, Optz = #optz{unique = Unique and not IsUnique, cache = Cachez, opt = Opt}, QLC = #simple_qlc{p = PVar, le = LE, line = Line, init_value = not_a_list, optz = Optz}, %% LE#prepared.join is not copied #prepared{qh = QLC, is_unique_objects = IsUnique or Unique, sort_info = SortInfo, sorted = Sorted, is_cached = IsCached or (Cachez =/= false)}.prep_sort(#qlc_sort{h = #prepared{sorted = yes}=Prep}, _Opt) -> Prep;prep_sort(#qlc_sort{h = #prepared{is_unique_objects = IsUniqueObjs}}=Q, Opt) -> S1 = sort_unique(IsUniqueObjs, Q), S = sort_tmpdir(S1, Opt), {SortInfo, Sorted} = sort_sort_info(S), #prepared{qh = S, is_cached = true, sort_info = SortInfo, sorted = Sorted, is_unique_objects = S#qlc_sort.unique or IsUniqueObjs}.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?