263 lines
6.5 KiB
SAS
263 lines
6.5 KiB
SAS
/**
|
|
@file
|
|
@brief dynamic where clause creation
|
|
@details Generates a where clause based on the following inputs:
|
|
|
|
@li The filter_RK (if provided)
|
|
@li The mode (if EDIT then filter for current records)
|
|
@li The user permissions (Row Level Security)
|
|
|
|
This macro should be used whenever surfacing data to the user. Note that
|
|
it is not possible to %include filerefs directly in a proc sql where clause.
|
|
The workaround is to use a data step view.
|
|
|
|
Note - DCLIB should be assigned.
|
|
|
|
@param [in] mode The mode. If EDIT, then current rows are returned. Valid
|
|
Values:
|
|
@li EDIT
|
|
@li VIEW
|
|
@li DLOAD - used in getrawdata
|
|
@li ULOAD - used by stagedata.sas to prevent restricted rows being submitted
|
|
|
|
@param [in] libds The target libref.dataset to which the filter will apply.
|
|
@param [in] filter_rk= (-1) The filter_rk, if available
|
|
@param [in] dclib= The libref of the DC control tables
|
|
@param [out] outref= The output fileref to create (containing the filter)
|
|
@param [out] outds= (work.query) The query dataset (if filter_rk supplied)
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mf_fmtdttm.sas
|
|
@li mf_getuser.sas
|
|
@li mf_getuniquefileref.sas
|
|
@li mf_getuniquename.sas
|
|
@li mf_nobs.sas
|
|
@li mp_abort.sas
|
|
@li mp_filtergenerate.sas
|
|
@li mpe_getgroups.sas
|
|
|
|
@version 9.3
|
|
@author 4GL Apps Ltd
|
|
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
|
and may not be re-distributed or re-sold without the express permission of
|
|
4GL Apps Ltd.
|
|
**/
|
|
|
|
%macro mpe_filtermaster(mode,libds,
|
|
dclib=,
|
|
filter_rk=-1,
|
|
outref=0,
|
|
outds=work.query
|
|
);
|
|
|
|
%put &sysmacroname entry vars:;
|
|
%put _local_;
|
|
|
|
%let mode=%upcase(&mode);
|
|
%let libds=%upcase(&libds);
|
|
|
|
|
|
%mp_abort(iftrue= (
|
|
&mode ne EDIT and &mode ne VIEW and &mode ne DLOAD and &mode ne ULOAD
|
|
)
|
|
,mac=&sysmacroname
|
|
,msg=%str(Invalid MODE: &mode)
|
|
)
|
|
%mp_abort(iftrue= (&outref = 0)
|
|
,mac=&sysmacroname
|
|
,msg=%str(Please provide a fileref!)
|
|
)
|
|
%mp_abort(iftrue= (&syscc ne 0)
|
|
,mac=&sysmacroname
|
|
,msg=%str(syscc=&syscc)
|
|
)
|
|
|
|
filename &outref temp;
|
|
|
|
/* ensure outputs exist */
|
|
data _null_;
|
|
file &outref;
|
|
put ' ';
|
|
run;
|
|
data &outds;
|
|
set &dclib..mpe_filtersource;
|
|
stop;
|
|
run;
|
|
|
|
/**
|
|
* Deal with FILTER_RK first
|
|
*/
|
|
%if &filter_rk gt 0 %then %do;
|
|
|
|
data _null_;
|
|
file &outref;
|
|
put '( '@@;
|
|
set &dclib..mpe_filteranytable(where=(filter_rk=&filter_rk));
|
|
call symputx('filter_hash',filter_hash,'l');
|
|
run;
|
|
|
|
proc sort data=&dclib..mpe_filtersource(where=(filter_hash="&filter_hash"))
|
|
out=&outds(drop=filter_hash filter_line processed_dttm);
|
|
by filter_line;
|
|
run;
|
|
%mp_filtergenerate(&outds,outref=&outref)
|
|
|
|
%end;
|
|
|
|
/* Now filter for current records if the MODE is EDIT or DLOAD */
|
|
%local varfrom varto;
|
|
%let varfrom=0;
|
|
|
|
proc sql;
|
|
select coalescec(var_txfrom,'0'), var_txto into: varfrom,:varto
|
|
from &dclib..MPE_TABLES
|
|
where &dc_dttmtfmt. lt tx_to
|
|
and libref="%scan(&libds,1,.)" and dsn="%scan(&libds,2,.)";
|
|
|
|
%put &=varfrom;
|
|
%put &=varto;
|
|
|
|
/**
|
|
* Check if the date variables were mentioned in the query
|
|
* This is a trigger for serving a historical view instead of current
|
|
* we skip this part when checking an ULOAD as there are no date vars
|
|
*/
|
|
%if &varfrom ne 0 and (&mode=EDIT or &mode=DLOAD) %then %do;
|
|
%local validityvars;
|
|
proc sql;
|
|
select count(*) into: validityvars
|
|
from &outds
|
|
where variable_nm in ("&varfrom","&varto");
|
|
%if &validityvars=0 %then %do;
|
|
data _null_;
|
|
file &outref mod;
|
|
length filter_text $32767;
|
|
varfrom=symget('varfrom');
|
|
varto=symget('varto');
|
|
filter_text=catx(' ',
|
|
'("%sysfunc(datetime(),',"%mf_fmtdttm()",')"dt <',varto,')'
|
|
);
|
|
if &filter_rk > 0 then put 'AND ' filter_text;
|
|
else put filter_text;
|
|
run;
|
|
%end;
|
|
%end;
|
|
|
|
/**
|
|
* Now do Row Level Security based on the MPE_ROW_LEVEL_SECURITY table
|
|
*/
|
|
|
|
/* first determine users group membership */
|
|
%mpe_getgroups(user=%mf_getuser(),outds=work.groups)
|
|
%local admin_check;
|
|
proc sql;
|
|
select count(*) into: admin_check
|
|
from work.groups
|
|
where groupname="&mpeadmins";
|
|
|
|
%put &sysmacroname: &=admin_check &=mpeadmins;
|
|
%if &admin_check=0 %then %do;
|
|
%local scopeval;
|
|
%if &mode=DLOAD %then %let scopeval=VIEW;
|
|
%if &mode=ULOAD %then %let scopeval=EDIT;
|
|
%else %let scopeval=&mode;
|
|
/* extract relevant rows */
|
|
%local rlsds;
|
|
%let rlsds=%mf_getuniquename();
|
|
proc sql;
|
|
create table work.&rlsds as
|
|
select rls_group,
|
|
rls_group_logic as group_logic,
|
|
rls_subgroup_logic as subgroup_logic,
|
|
rls_subgroup_id as subgroup_id,
|
|
rls_variable_nm as variable_nm,
|
|
rls_operator_nm as operator_nm,
|
|
rls_raw_value as raw_value
|
|
from &mpelib..mpe_row_level_security
|
|
where &dc_dttmtfmt. lt tx_to
|
|
and rls_scope in ("&scopeval",'ALL')
|
|
and upcase(rls_group) in (select upcase(groupname) from work.groups)
|
|
and rls_libref="%scan(&libds,1,.)"
|
|
and rls_table="%scan(&libds,2,.)"
|
|
and rls_active=1
|
|
order by rls_group,rls_subgroup_id;
|
|
%if &sqlobs>0 %then %do;
|
|
/* check if we currently have filter or not */
|
|
data ;
|
|
infile &outref end=eof;
|
|
input;
|
|
if _n_=1 and eof and cats(_infile_)='' then newfilter=1;
|
|
output;
|
|
stop;
|
|
run;
|
|
data _null_;
|
|
set &syslast;
|
|
file &outref mod;
|
|
if newfilter=1 then put '(';
|
|
else put 'AND (';
|
|
run;
|
|
|
|
/* loop through and apply filters for each group membership */
|
|
%local fref ds;
|
|
%let fref=%mf_getuniquefileref();
|
|
%let ds=%mf_getuniquename();
|
|
|
|
proc sql noprint;
|
|
select distinct rls_group into : group1 -
|
|
from work.&rlsds;
|
|
|
|
%do i=1 %to &sqlobs;
|
|
data work.&ds;
|
|
set work.&rlsds;
|
|
where rls_group="&&group&i";
|
|
drop rls_group;
|
|
run;
|
|
%mp_filtergenerate(&ds,outref=&fref)
|
|
data _null_;
|
|
infile &fref;
|
|
file &outref mod;
|
|
input;
|
|
if &i>1 and _n_=1 then put ' OR ';
|
|
put _infile_;
|
|
run;
|
|
%end;
|
|
data _null_;
|
|
file &outref mod;
|
|
put ')';
|
|
run;
|
|
%end; /* &sqlobs>0 */
|
|
%else %do;
|
|
%put &sysmacroname: no matching groups;
|
|
data _null_;
|
|
set work.groups;
|
|
putlog (_all_)(=);
|
|
run;
|
|
%end;
|
|
%mp_abort(iftrue= (&syscc>0)
|
|
,mac=&sysmacroname
|
|
,msg=%str(Row Level Security Generation Error)
|
|
)
|
|
%end; /* &admin_check=0 */
|
|
|
|
%put leaving &sysmacroname with the following query:;
|
|
|
|
%local empty;
|
|
%let empty=0;
|
|
data _null_;
|
|
infile &outref end=eof;
|
|
input;
|
|
putlog _infile_;
|
|
if _n_=1 and eof and cats(_infile_)='' then do;
|
|
put '1=1';
|
|
call symputx('empty',1,'l');
|
|
end;
|
|
run;
|
|
%if &empty=1 %then %do;
|
|
data _null_;
|
|
file &outref;
|
|
put '1=1';
|
|
run;
|
|
%end;
|
|
|
|
%mend mpe_filtermaster;
|