mirror of
https://github.com/sasjs/core.git
synced 2026-01-10 02:40:05 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9de512cfc7 | ||
|
|
cadafcc86b | ||
|
|
5f805b006f | ||
|
|
c6b65366b7 | ||
|
|
51ddd9c1e5 | ||
|
|
20bf3b86af | ||
|
|
de67cd329b | ||
|
|
779e4942c7 | ||
|
|
a69a1ac7f0 | ||
|
|
2a644d6c2b | ||
|
|
843930c666 | ||
|
|
90d69af7ee | ||
|
|
b7bafb49f4 | ||
|
|
2fa9e48286 | ||
|
|
5cee93c7bd |
363
all.sas
363
all.sas
@@ -1694,7 +1694,7 @@ Usage:
|
|||||||
input;
|
input;
|
||||||
i=1;
|
i=1;
|
||||||
stoploop=0;
|
stoploop=0;
|
||||||
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
|
if _n_ ge &logline-15 and stoploop=0 then do until (i>22);
|
||||||
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
||||||
input;
|
input;
|
||||||
i+1;
|
i+1;
|
||||||
@@ -2936,20 +2936,24 @@ run;
|
|||||||
%mend;/**
|
%mend;/**
|
||||||
@file
|
@file
|
||||||
@brief Drops tables / views (if they exist) without warnings in the log
|
@brief Drops tables / views (if they exist) without warnings in the log
|
||||||
@details
|
@details Useful for dropping tables when you're not sure they exist, or if
|
||||||
|
you are not sure whether they are a dataset or view. Also efficient for
|
||||||
|
dropping multiple tables / views.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
create table data1 as select * from sashelp.class;
|
create table data1 as select * from sashelp.class;
|
||||||
create view view2 as select * from sashelp.class;
|
create view view2 as select * from sashelp.class;
|
||||||
%mp_dropmembers(list=data1 view2)
|
%mp_dropmembers(data1 view2, libref=WORK)
|
||||||
|
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_isblank.sas
|
@li mf_isblank.sas
|
||||||
|
|
||||||
|
|
||||||
@param list space separated list of datasets / views
|
@param list space separated list of datasets / views, WITHOUT libref
|
||||||
@param libref= can only drop from a single library at a time
|
@param libref= (WORK) Note - you can only drop from a single library at a time
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@@ -2970,7 +2974,7 @@ run;
|
|||||||
delete &list;
|
delete &list;
|
||||||
delete &list /mtype=view;
|
delete &list /mtype=view;
|
||||||
run;
|
run;
|
||||||
%mend;/**
|
%mend mp_dropmembers;/**
|
||||||
@file
|
@file
|
||||||
@brief Create a CARDS file from a SAS dataset.
|
@brief Create a CARDS file from a SAS dataset.
|
||||||
@details Uses dataset attributes to convert all data into datalines.
|
@details Uses dataset attributes to convert all data into datalines.
|
||||||
@@ -3412,12 +3416,13 @@ run;
|
|||||||
@returns The &outds table containing any bad rows, plus a REASON_CD column.
|
@returns The &outds table containing any bad rows, plus a REASON_CD column.
|
||||||
|
|
||||||
@param [in] inds The table to be checked, with the format above
|
@param [in] inds The table to be checked, with the format above
|
||||||
@param [in] targetds= The target dataset against which to verify VARIABLE_NM
|
@param [in] targetds= The target dataset against which to verify VARIABLE_NM.
|
||||||
|
This must be available (ie, the library must be assigned).
|
||||||
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
||||||
@param [out] outds= The output table, which is a copy of the &inds. table
|
@param [out] outds= The output table, which is a copy of the &inds. table
|
||||||
plus a REASON_CD column, containing only bad records. If bad records found,
|
plus a REASON_CD column, containing only bad records. If bad records found,
|
||||||
the SYSCC value will be set to 1008 (general data problem). Downstream
|
the SYSCC value will be set to 1008 (general data problem). Downstream
|
||||||
processes should check this table (and return code) before continuing.
|
processes should check this table (and return code) before continuing.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@@ -3463,41 +3468,52 @@ run;
|
|||||||
* quotes, commas, periods and spaces.
|
* quotes, commas, periods and spaces.
|
||||||
* Only numeric values should remain
|
* Only numeric values should remain
|
||||||
*/
|
*/
|
||||||
%local reason_cd;
|
%local reason_cd nobs;
|
||||||
|
%let nobs=0;
|
||||||
data &outds;
|
data &outds;
|
||||||
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
|
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
|
||||||
OPERATOR_NM $10 RAW_VALUE $4000;*/
|
OPERATOR_NM $10 RAW_VALUE $4000;*/
|
||||||
set &inds;
|
set &inds;
|
||||||
length reason_cd $32;
|
length reason_cd $4032;
|
||||||
|
|
||||||
/* closed list checks */
|
/* closed list checks */
|
||||||
if GROUP_LOGIC not in ('AND','OR') then do;
|
if GROUP_LOGIC not in ('AND','OR') then do;
|
||||||
REASON_CD='GROUP_LOGIC should be either AND or OR';
|
REASON_CD='GROUP_LOGIC should be AND/OR, not:'!!cats(GROUP_LOGIC);
|
||||||
putlog REASON_CD= GROUP_LOGIC=;
|
putlog REASON_CD= GROUP_LOGIC=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if SUBGROUP_LOGIC not in ('AND','OR') then do;
|
if SUBGROUP_LOGIC not in ('AND','OR') then do;
|
||||||
REASON_CD='SUBGROUP_LOGIC should be either AND or OR';
|
REASON_CD='SUBGROUP_LOGIC should be AND/OR, not:'!!cats(SUBGROUP_LOGIC);
|
||||||
putlog REASON_CD= SUBGROUP_LOGIC=;
|
putlog REASON_CD= SUBGROUP_LOGIC=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if mod(SUBGROUP_ID,1) ne 0 then do;
|
if mod(SUBGROUP_ID,1) ne 0 then do;
|
||||||
REASON_CD='SUBGROUP_ID should be integer';
|
REASON_CD='SUBGROUP_ID should be integer, not '!!left(subgroup_id);
|
||||||
putlog REASON_CD= SUBGROUP_ID=;
|
putlog REASON_CD= SUBGROUP_ID=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if upcase(VARIABLE_NM) not in
|
if upcase(VARIABLE_NM) not in
|
||||||
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
|
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
|
||||||
then do;
|
then do;
|
||||||
REASON_CD="VARIABLE_NM not in &targetds";
|
REASON_CD="Variable "!!cats(variable_nm)!!" not in &targetds";
|
||||||
putlog REASON_CD= VARIABLE_NM=;
|
putlog REASON_CD= VARIABLE_NM=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if OPERATOR_NM not in
|
if OPERATOR_NM not in
|
||||||
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
||||||
then do;
|
then do;
|
||||||
REASON_CD='Invalid OPERATOR_NM';
|
REASON_CD='Invalid OPERATOR_NM: '!!left(OPERATOR_NM);
|
||||||
putlog REASON_CD= OPERATOR_NM=;
|
putlog REASON_CD= OPERATOR_NM=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -3507,8 +3523,10 @@ data &outds;
|
|||||||
if substr(raw_value,1,1) ne '('
|
if substr(raw_value,1,1) ne '('
|
||||||
or substr(cats(reverse(raw_value)),1,1) ne ')'
|
or substr(cats(reverse(raw_value)),1,1) ne ')'
|
||||||
then do;
|
then do;
|
||||||
REASON_CD='Missing brackets in RAW_VALUE';
|
REASON_CD='Missing start/end bracket in RAW_VALUE';
|
||||||
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
|
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
|
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
|
||||||
@@ -3529,27 +3547,24 @@ data &outds;
|
|||||||
/* output records that contain values other than digits and spaces */
|
/* output records that contain values other than digits and spaces */
|
||||||
if notdigit(compress(raw_value3,' '))>0 then do;
|
if notdigit(compress(raw_value3,' '))>0 then do;
|
||||||
putlog raw_value3= $hex32.;
|
putlog raw_value3= $hex32.;
|
||||||
REASON_CD='Invalid RAW_VALUE';
|
REASON_CD=cats('Invalid RAW_VALUE:',raw_value);
|
||||||
putlog REASON_CD= raw_value= raw_value1= raw_value2= raw_value3=;
|
putlog REASON_CD= raw_value= raw_value1= raw_value2= raw_value3=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%local nobs;
|
|
||||||
%let nobs=0;
|
|
||||||
data _null_;
|
data _null_;
|
||||||
set &outds end=last;
|
set &outds end=last;
|
||||||
putlog (_all_)(=);
|
putlog (_all_)(=);
|
||||||
if last then do;
|
|
||||||
call symputx('REASON_CD',reason_cd,'l');
|
|
||||||
call symputx('nobs',_n_,'l');
|
|
||||||
end;
|
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%mp_abort(iftrue=(&abort=YES and &nobs>0),
|
%mp_abort(iftrue=(&abort=YES and &nobs>0),
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(&nobs filter issues in &inds, reason: &reason_cd, details in &outds)
|
msg=%str(Data issue: %superq(reason_cd))
|
||||||
)
|
)
|
||||||
|
|
||||||
%if &nobs>0 %then %do;
|
%if &nobs>0 %then %do;
|
||||||
@@ -3768,7 +3783,8 @@ filename &fref1 clear;
|
|||||||
run;
|
run;
|
||||||
%mp_abort(
|
%mp_abort(
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(Filter issues in &inref: %quote(&reason_cd))
|
msg=%str(Filter validation issues. ERR=%superq(SYSERRORTEXT)
|
||||||
|
, WARN=%superq(SYSWARNINGTEXT) )
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%let syscc=1008;
|
%let syscc=1008;
|
||||||
@@ -5060,7 +5076,7 @@ create table &outds (rename=(
|
|||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%put output location=&jref;
|
%put output location=&jref;
|
||||||
%if &action=OPEN %then %do;
|
%if &action=OPEN %then %do;
|
||||||
OPTIONS NOBOMFILE;
|
options nobomfile;
|
||||||
data _null_;file &jref encoding='utf-8';
|
data _null_;file &jref encoding='utf-8';
|
||||||
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
|
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
|
||||||
run;
|
run;
|
||||||
@@ -5713,7 +5729,15 @@ run;
|
|||||||
|
|
||||||
%mp_searchcols(libs=sashelp work, cols=name sex age)
|
%mp_searchcols(libs=sashelp work, cols=name sex age)
|
||||||
|
|
||||||
@param libs=
|
@param libs=(SASHELP) Space separated list of libraries to search for columns
|
||||||
|
@param cols= Space separated list of column names to search for (not case
|
||||||
|
sensitive)
|
||||||
|
@param outds=(mp_searchcols) the table to create with the results. Will have
|
||||||
|
one line per table match.
|
||||||
|
@param match=(ANY) The match type. Valid values:
|
||||||
|
@li ANY - The table contains at least one of the columns
|
||||||
|
@li WILD - The table contains a column with a name that partially matches
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
**/
|
**/
|
||||||
@@ -5721,6 +5745,7 @@ run;
|
|||||||
%macro mp_searchcols(libs=sashelp
|
%macro mp_searchcols(libs=sashelp
|
||||||
,cols=
|
,cols=
|
||||||
,outds=mp_searchcols
|
,outds=mp_searchcols
|
||||||
|
,match=ANY
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
%put &sysmacroname process began at %sysfunc(datetime(),datetime19.);
|
%put &sysmacroname process began at %sysfunc(datetime(),datetime19.);
|
||||||
@@ -5742,8 +5767,10 @@ create table _data_ as
|
|||||||
%end;
|
%end;
|
||||||
order by 1,2,3;
|
order by 1,2,3;
|
||||||
|
|
||||||
|
%local tempds;
|
||||||
|
%let tempds=&syslast;
|
||||||
data &outds;
|
data &outds;
|
||||||
set &syslast;
|
set &tempds;
|
||||||
length cols matchcols $32767;
|
length cols matchcols $32767;
|
||||||
cols=upcase(symget('cols'));
|
cols=upcase(symget('cols'));
|
||||||
colcount=countw(cols);
|
colcount=countw(cols);
|
||||||
@@ -5757,10 +5784,29 @@ data &outds;
|
|||||||
retain matchcols;
|
retain matchcols;
|
||||||
matchcols='';
|
matchcols='';
|
||||||
end;
|
end;
|
||||||
|
%if &match=ANY %then %do;
|
||||||
if findw(cols,name,,'spit') then do;
|
if findw(cols,name,,'spit') then do;
|
||||||
sumcols+1;
|
sumcols+1;
|
||||||
matchcols=cats(matchcols)!!' '!!cats(name);
|
matchcols=cats(matchcols)!!' '!!cats(name);
|
||||||
end;
|
end;
|
||||||
|
%end;
|
||||||
|
%else %if &match=WILD %then %do;
|
||||||
|
if _n_=1 then do;
|
||||||
|
retain wcount;
|
||||||
|
wcount=countw(cols);
|
||||||
|
drop wcount;
|
||||||
|
end;
|
||||||
|
do i=1 to wcount;
|
||||||
|
length curword $32;
|
||||||
|
curword=scan(cols,i,' ');
|
||||||
|
drop curword;
|
||||||
|
if index(name,cats(curword)) then do;
|
||||||
|
sumcols+1;
|
||||||
|
matchcols=cats(matchcols)!!' '!!cats(curword);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
%end;
|
||||||
|
|
||||||
if last.memname then do;
|
if last.memname then do;
|
||||||
if sumcols>0 then output;
|
if sumcols>0 then output;
|
||||||
if sumcols=colcount then putlog "Full Match: " libname memname;
|
if sumcols=colcount then putlog "Full Match: " libname memname;
|
||||||
@@ -5770,10 +5816,11 @@ run;
|
|||||||
|
|
||||||
proc sort; by descending sumcols memname libname; run;
|
proc sort; by descending sumcols memname libname; run;
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
drop table &tempds;
|
||||||
%put &sysmacroname process finished at %sysfunc(datetime(),datetime19.);
|
%put &sysmacroname process finished at %sysfunc(datetime(),datetime19.);
|
||||||
|
|
||||||
%mend;
|
%mend mp_searchcols;/**
|
||||||
/**
|
|
||||||
@file
|
@file
|
||||||
@brief Searches all data in a library
|
@brief Searches all data in a library
|
||||||
@details
|
@details
|
||||||
@@ -8890,7 +8937,7 @@ data _null_;
|
|||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%put output location=&jref; ';
|
put '%put output location=&jref; ';
|
||||||
put '%if &action=OPEN %then %do; ';
|
put '%if &action=OPEN %then %do; ';
|
||||||
put ' OPTIONS NOBOMFILE; ';
|
put ' options nobomfile; ';
|
||||||
put ' data _null_;file &jref encoding=''utf-8''; ';
|
put ' data _null_;file &jref encoding=''utf-8''; ';
|
||||||
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
@@ -13504,7 +13551,7 @@ data _null_;
|
|||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%put output location=&jref; ';
|
put '%put output location=&jref; ';
|
||||||
put '%if &action=OPEN %then %do; ';
|
put '%if &action=OPEN %then %do; ';
|
||||||
put ' OPTIONS NOBOMFILE; ';
|
put ' options nobomfile; ';
|
||||||
put ' data _null_;file &jref encoding=''utf-8''; ';
|
put ' data _null_;file &jref encoding=''utf-8''; ';
|
||||||
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
@@ -16334,8 +16381,8 @@ run;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access
|
@param [in] access_token_var= The global macro variable to contain the
|
||||||
token
|
access token
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
@li password
|
@li password
|
||||||
@li authorization_code
|
@li authorization_code
|
||||||
@@ -16474,123 +16521,143 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
|
|
||||||
/* start loop */
|
/* start loop */
|
||||||
%do fid=1 %to &flowcnt;
|
%do fid=1 %to &flowcnt;
|
||||||
%put preparing job attributes for flow &&flow&fid;
|
|
||||||
%local jds jcnt;
|
|
||||||
data &jds(drop=_contextName _program);
|
|
||||||
set &inds(where=(flow_id=&&flow&fid));
|
|
||||||
if _contextName='' then _contextName="SAS Job Execution compute context";
|
|
||||||
call symputx(cats('job',_n_),_program,'l');
|
|
||||||
call symputx(cats('context',_n_),_contextName,'l');
|
|
||||||
call symputx('jcnt',_n_,'l');
|
|
||||||
run;
|
|
||||||
%put exporting job variables in json format;
|
|
||||||
%do jid=1 %to &jcnt;
|
|
||||||
data &jjson;
|
|
||||||
set &jds;
|
|
||||||
if _n_=&jid then do;
|
|
||||||
output;
|
|
||||||
stop;
|
|
||||||
end;
|
|
||||||
run;
|
|
||||||
proc json out=&jfref;
|
|
||||||
export &jjson / nosastags fmtnumeric;
|
|
||||||
run;
|
|
||||||
data _null_;
|
|
||||||
infile &jfref lrecl=32767;
|
|
||||||
input;
|
|
||||||
jparams='jparams'!!left(symget('jid'));
|
|
||||||
call symputx(jparams,substr(_infile_,3,length(_infile_)-4));
|
|
||||||
run;
|
|
||||||
%local jobuid&jid;
|
|
||||||
%let jobuid&jid=0; /* used in next loop */
|
|
||||||
%end;
|
|
||||||
%local concurrency completed;
|
|
||||||
%let concurrency=0;
|
|
||||||
%let completed=0;
|
|
||||||
proc sql; drop table &jdsrunning;
|
|
||||||
%do jid=1 %to &jcnt;
|
|
||||||
/**
|
|
||||||
* now we can execute the jobs up to the maxconcurrency setting
|
|
||||||
*/
|
|
||||||
%if "&&job&jid" ne "0" %then %do; /* this var is zero if job finished */
|
|
||||||
|
|
||||||
/* check to see if the job finished in the previous round */
|
%if not ( &raise_err and &syscc ) %then %do;
|
||||||
%if %sysfunc(exist(&outds))=1 %then %do;
|
|
||||||
%local jobcheck; %let jobcheck=0;
|
%put preparing job attributes for flow &&flow&fid;
|
||||||
proc sql noprint;
|
%local jds jcnt;
|
||||||
select count(*) into: jobcheck
|
data &jds(drop=_contextName _program);
|
||||||
from &outds where uuid="&&jobuid&jid";
|
set &inds(where=(flow_id=&&flow&fid));
|
||||||
%if &jobcheck>0 %then %do;
|
if _contextName='' then _contextName="SAS Job Execution compute context";
|
||||||
%put &&job&jid in flow &fid with uid &&jobuid&jid completed!;
|
call symputx(cats('job',_n_),_program,'l');
|
||||||
%let job&jid=0;
|
call symputx(cats('context',_n_),_contextName,'l');
|
||||||
|
call symputx('jcnt',_n_,'l');
|
||||||
|
run;
|
||||||
|
%put exporting job variables in json format;
|
||||||
|
%do jid=1 %to &jcnt;
|
||||||
|
data &jjson;
|
||||||
|
set &jds;
|
||||||
|
if _n_=&jid then do;
|
||||||
|
output;
|
||||||
|
stop;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
proc json out=&jfref;
|
||||||
|
export &jjson / nosastags fmtnumeric;
|
||||||
|
run;
|
||||||
|
data _null_;
|
||||||
|
infile &jfref lrecl=32767;
|
||||||
|
input;
|
||||||
|
jparams='jparams'!!left(symget('jid'));
|
||||||
|
call symputx(jparams,substr(_infile_,3,length(_infile_)-4));
|
||||||
|
run;
|
||||||
|
%local jobuid&jid;
|
||||||
|
%let jobuid&jid=0; /* used in next loop */
|
||||||
|
%end;
|
||||||
|
%local concurrency completed;
|
||||||
|
%let concurrency=0;
|
||||||
|
%let completed=0;
|
||||||
|
proc sql; drop table &jdsrunning;
|
||||||
|
%do jid=1 %to &jcnt;
|
||||||
|
/**
|
||||||
|
* now we can execute the jobs up to the maxconcurrency setting
|
||||||
|
*/
|
||||||
|
%if "&&job&jid" ne "0" %then %do; /* this var is zero if job finished */
|
||||||
|
|
||||||
|
/* check to see if the job finished in the previous round */
|
||||||
|
%if %sysfunc(exist(&outds))=1 %then %do;
|
||||||
|
%local jobcheck; %let jobcheck=0;
|
||||||
|
proc sql noprint;
|
||||||
|
select count(*) into: jobcheck
|
||||||
|
from &outds where uuid="&&jobuid&jid";
|
||||||
|
%if &jobcheck>0 %then %do;
|
||||||
|
%put &&job&jid in flow &fid with uid &&jobuid&jid completed!;
|
||||||
|
%let job&jid=0;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* check if job was triggered and, if
|
||||||
|
so, if we have enough slots to run? */
|
||||||
|
%if ("&&jobuid&jid"="0") and (&concurrency<&maxconcurrency) %then %do;
|
||||||
|
|
||||||
|
/* But only start if no issues detected so far */
|
||||||
|
%if not ( &raise_err and &syscc ) %then %do;
|
||||||
|
|
||||||
|
%local jobname jobpath;
|
||||||
|
%let jobname=%scan(&&job&jid,-1,/);
|
||||||
|
%let jobpath=
|
||||||
|
%substr(&&job&jid,1,%length(&&job&jid)-%length(&jobname)-1);
|
||||||
|
|
||||||
|
%put executing &jobpath/&jobname with paramstring &&jparams&jid;
|
||||||
|
%mv_jobexecute(path=&jobpath
|
||||||
|
,name=&jobname
|
||||||
|
,paramstring=%superq(jparams&jid)
|
||||||
|
,outds=&jdsapp
|
||||||
|
)
|
||||||
|
data &jdsapp;
|
||||||
|
format jobparams $32767.;
|
||||||
|
set &jdsapp(where=(method='GET' and rel='state'));
|
||||||
|
jobparams=symget("jparams&jid");
|
||||||
|
/* uri here has the /state suffix */
|
||||||
|
uuid=scan(uri,-2,'/');
|
||||||
|
call symputx("jobuid&jid",uuid,'l');
|
||||||
|
run;
|
||||||
|
proc append base=&jdsrunning data=&jdsapp;
|
||||||
|
run;
|
||||||
|
%let concurrency=%eval(&concurrency+1);
|
||||||
|
/* sleep one second after every request to smooth the impact */
|
||||||
|
data _null_;
|
||||||
|
call sleep(1,1);
|
||||||
|
run;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do; /* Job was skipped due to problems */
|
||||||
|
|
||||||
|
%put jobid &&job&jid in flow &fid skipped due to SYSCC (&syscc);
|
||||||
|
%let completed = %eval(&completed+1);
|
||||||
|
%let job&jid=0; /* Indicate job has finished */
|
||||||
|
|
||||||
|
%end;
|
||||||
|
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
|
%if &jid=&jcnt %then %do;
|
||||||
|
/* we are at the end of the loop - check which jobs have finished */
|
||||||
|
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref
|
||||||
|
,raise_err=&raise_err,mdebug=&mdebug)
|
||||||
|
%local done;
|
||||||
|
%let done=%mf_nobs(&jdswaitfor);
|
||||||
|
%if &done>0 %then %do;
|
||||||
|
%let completed=%eval(&completed+&done);
|
||||||
|
%let concurrency=%eval(&concurrency-&done);
|
||||||
|
data &jdsapp;
|
||||||
|
set &jdswaitfor;
|
||||||
|
flow_id=&&flow&fid;
|
||||||
|
uuid=scan(uri,-1,'/');
|
||||||
|
run;
|
||||||
|
proc append base=&outds data=&jdsapp;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
proc sql;
|
||||||
|
delete from &jdsrunning
|
||||||
|
where uuid in (select uuid from &outds
|
||||||
|
where state in ('canceled','completed','failed')
|
||||||
|
);
|
||||||
|
|
||||||
/* check if job was triggered and if so, if we have enough slots to run */
|
/* loop again if jobs are left */
|
||||||
%if "&&jobuid&jid"="0" and &concurrency<&maxconcurrency %then %do;
|
%if &completed < &jcnt %then %do;
|
||||||
%local jobname jobpath;
|
%let jid=0;
|
||||||
%let jobname=%scan(&&job&jid,-1,/);
|
%put looping flow &fid again;
|
||||||
%let jobpath=
|
%put &completed of &jcnt jobs completed, &concurrency jobs running;
|
||||||
%substr(&&job&jid,1,%length(&&job&jid)-%length(&jobname)-1);
|
%end;
|
||||||
%put executing &jobpath/&jobname with paramstring &&jparams&jid;
|
|
||||||
%mv_jobexecute(path=&jobpath
|
|
||||||
,name=&jobname
|
|
||||||
,paramstring=%superq(jparams&jid)
|
|
||||||
,outds=&jdsapp
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
data &jdsapp;
|
|
||||||
format jobparams $32767.;
|
|
||||||
set &jdsapp(where=(method='GET' and rel='state'));
|
|
||||||
jobparams=symget("jparams&jid");
|
|
||||||
/* uri here has the /state suffix */
|
|
||||||
uuid=scan(uri,-2,'/');
|
|
||||||
call symputx("jobuid&jid",uuid,'l');
|
|
||||||
run;
|
|
||||||
proc append base=&jdsrunning data=&jdsapp;
|
|
||||||
run;
|
|
||||||
%let concurrency=%eval(&concurrency+1);
|
|
||||||
/* sleep one second after every request to smooth the impact */
|
|
||||||
data _null_;
|
|
||||||
call sleep(1,1);
|
|
||||||
run;
|
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%if &jid=&jcnt %then %do;
|
|
||||||
/* we are at the end of the loop - time to see which jobs have finished */
|
|
||||||
%mv_jobwaitfor(ANY
|
|
||||||
,inds=&jdsrunning
|
|
||||||
,outds=&jdswaitfor
|
|
||||||
,outref=&outref
|
|
||||||
,raise_err=&raise_err
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
%local done;
|
|
||||||
%let done=%mf_nobs(&jdswaitfor);
|
|
||||||
%if &done>0 %then %do;
|
|
||||||
%let completed=%eval(&completed+&done);
|
|
||||||
%let concurrency=%eval(&concurrency-&done);
|
|
||||||
data &jdsapp;
|
|
||||||
set &jdswaitfor;
|
|
||||||
flow_id=&&flow&fid;
|
|
||||||
uuid=scan(uri,-1,'/');
|
|
||||||
run;
|
|
||||||
proc append base=&outds data=&jdsapp;
|
|
||||||
run;
|
|
||||||
%end;
|
|
||||||
proc sql;
|
|
||||||
delete from &jdsrunning
|
|
||||||
where uuid in (select uuid from &outds
|
|
||||||
where state in ('canceled','completed','failed')
|
|
||||||
);
|
|
||||||
|
|
||||||
/* loop again if jobs are left */
|
%end;
|
||||||
%if &completed < &jcnt %then %do;
|
%else %do;
|
||||||
%let jid=0;
|
|
||||||
%put looping flow &fid again - &completed of &jcnt jobs completed,
|
%put Flow &&flow&fid skipped due to SYSCC (&syscc);
|
||||||
&concurrency jobs running;
|
|
||||||
%end;
|
|
||||||
%end;
|
|
||||||
%end;
|
%end;
|
||||||
/* back up and execute the next flow */
|
/* back up and execute the next flow */
|
||||||
%end;
|
%end;
|
||||||
@@ -17626,6 +17693,8 @@ filename &fref1 clear;
|
|||||||
%macro ml_json();
|
%macro ml_json();
|
||||||
data _null_;
|
data _null_;
|
||||||
file "%sysfunc(pathname(work))/ml_json.lua";
|
file "%sysfunc(pathname(work))/ml_json.lua";
|
||||||
|
put '-- NOTE - THE COPYRIGHT BELOW IS IN RELATION TO THE JSON.LUA FILE ONLY ';
|
||||||
|
put '-- THIS FILE STARTS ON THE NEXT LINE AND WILL FINISH WITH "JSON.LUA ENDS HERE" ';
|
||||||
put '-- ';
|
put '-- ';
|
||||||
put '-- json.lua ';
|
put '-- json.lua ';
|
||||||
put '-- ';
|
put '-- ';
|
||||||
@@ -17997,6 +18066,8 @@ data _null_;
|
|||||||
put 'end ';
|
put 'end ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put 'return json ';
|
put 'return json ';
|
||||||
|
put ' ';
|
||||||
|
put '-- JSON.LUA ENDS HERE ';
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%inc "%sysfunc(pathname(work))/ml_json.lua";
|
%inc "%sysfunc(pathname(work))/ml_json.lua";
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
input;
|
input;
|
||||||
i=1;
|
i=1;
|
||||||
stoploop=0;
|
stoploop=0;
|
||||||
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
|
if _n_ ge &logline-15 and stoploop=0 then do until (i>22);
|
||||||
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
||||||
input;
|
input;
|
||||||
i+1;
|
i+1;
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Drops tables / views (if they exist) without warnings in the log
|
@brief Drops tables / views (if they exist) without warnings in the log
|
||||||
@details
|
@details Useful for dropping tables when you're not sure they exist, or if
|
||||||
|
you are not sure whether they are a dataset or view. Also efficient for
|
||||||
|
dropping multiple tables / views.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
create table data1 as select * from sashelp.class;
|
create table data1 as select * from sashelp.class;
|
||||||
create view view2 as select * from sashelp.class;
|
create view view2 as select * from sashelp.class;
|
||||||
%mp_dropmembers(list=data1 view2)
|
%mp_dropmembers(data1 view2, libref=WORK)
|
||||||
|
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_isblank.sas
|
@li mf_isblank.sas
|
||||||
|
|
||||||
|
|
||||||
@param list space separated list of datasets / views
|
@param list space separated list of datasets / views, WITHOUT libref
|
||||||
@param libref= can only drop from a single library at a time
|
@param libref= (WORK) Note - you can only drop from a single library at a time
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@@ -35,4 +39,4 @@
|
|||||||
delete &list;
|
delete &list;
|
||||||
delete &list /mtype=view;
|
delete &list /mtype=view;
|
||||||
run;
|
run;
|
||||||
%mend;
|
%mend mp_dropmembers;
|
||||||
@@ -33,12 +33,13 @@
|
|||||||
@returns The &outds table containing any bad rows, plus a REASON_CD column.
|
@returns The &outds table containing any bad rows, plus a REASON_CD column.
|
||||||
|
|
||||||
@param [in] inds The table to be checked, with the format above
|
@param [in] inds The table to be checked, with the format above
|
||||||
@param [in] targetds= The target dataset against which to verify VARIABLE_NM
|
@param [in] targetds= The target dataset against which to verify VARIABLE_NM.
|
||||||
|
This must be available (ie, the library must be assigned).
|
||||||
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
||||||
@param [out] outds= The output table, which is a copy of the &inds. table
|
@param [out] outds= The output table, which is a copy of the &inds. table
|
||||||
plus a REASON_CD column, containing only bad records. If bad records found,
|
plus a REASON_CD column, containing only bad records. If bad records found,
|
||||||
the SYSCC value will be set to 1008 (general data problem). Downstream
|
the SYSCC value will be set to 1008 (general data problem). Downstream
|
||||||
processes should check this table (and return code) before continuing.
|
processes should check this table (and return code) before continuing.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@@ -84,41 +85,52 @@
|
|||||||
* quotes, commas, periods and spaces.
|
* quotes, commas, periods and spaces.
|
||||||
* Only numeric values should remain
|
* Only numeric values should remain
|
||||||
*/
|
*/
|
||||||
%local reason_cd;
|
%local reason_cd nobs;
|
||||||
|
%let nobs=0;
|
||||||
data &outds;
|
data &outds;
|
||||||
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
|
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
|
||||||
OPERATOR_NM $10 RAW_VALUE $4000;*/
|
OPERATOR_NM $10 RAW_VALUE $4000;*/
|
||||||
set &inds;
|
set &inds;
|
||||||
length reason_cd $32;
|
length reason_cd $4032;
|
||||||
|
|
||||||
/* closed list checks */
|
/* closed list checks */
|
||||||
if GROUP_LOGIC not in ('AND','OR') then do;
|
if GROUP_LOGIC not in ('AND','OR') then do;
|
||||||
REASON_CD='GROUP_LOGIC should be either AND or OR';
|
REASON_CD='GROUP_LOGIC should be AND/OR, not:'!!cats(GROUP_LOGIC);
|
||||||
putlog REASON_CD= GROUP_LOGIC=;
|
putlog REASON_CD= GROUP_LOGIC=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if SUBGROUP_LOGIC not in ('AND','OR') then do;
|
if SUBGROUP_LOGIC not in ('AND','OR') then do;
|
||||||
REASON_CD='SUBGROUP_LOGIC should be either AND or OR';
|
REASON_CD='SUBGROUP_LOGIC should be AND/OR, not:'!!cats(SUBGROUP_LOGIC);
|
||||||
putlog REASON_CD= SUBGROUP_LOGIC=;
|
putlog REASON_CD= SUBGROUP_LOGIC=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if mod(SUBGROUP_ID,1) ne 0 then do;
|
if mod(SUBGROUP_ID,1) ne 0 then do;
|
||||||
REASON_CD='SUBGROUP_ID should be integer';
|
REASON_CD='SUBGROUP_ID should be integer, not '!!left(subgroup_id);
|
||||||
putlog REASON_CD= SUBGROUP_ID=;
|
putlog REASON_CD= SUBGROUP_ID=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if upcase(VARIABLE_NM) not in
|
if upcase(VARIABLE_NM) not in
|
||||||
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
|
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
|
||||||
then do;
|
then do;
|
||||||
REASON_CD="VARIABLE_NM not in &targetds";
|
REASON_CD="Variable "!!cats(variable_nm)!!" not in &targetds";
|
||||||
putlog REASON_CD= VARIABLE_NM=;
|
putlog REASON_CD= VARIABLE_NM=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if OPERATOR_NM not in
|
if OPERATOR_NM not in
|
||||||
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
||||||
then do;
|
then do;
|
||||||
REASON_CD='Invalid OPERATOR_NM';
|
REASON_CD='Invalid OPERATOR_NM: '!!left(OPERATOR_NM);
|
||||||
putlog REASON_CD= OPERATOR_NM=;
|
putlog REASON_CD= OPERATOR_NM=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -128,8 +140,10 @@ data &outds;
|
|||||||
if substr(raw_value,1,1) ne '('
|
if substr(raw_value,1,1) ne '('
|
||||||
or substr(cats(reverse(raw_value)),1,1) ne ')'
|
or substr(cats(reverse(raw_value)),1,1) ne ')'
|
||||||
then do;
|
then do;
|
||||||
REASON_CD='Missing brackets in RAW_VALUE';
|
REASON_CD='Missing start/end bracket in RAW_VALUE';
|
||||||
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
|
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
|
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
|
||||||
@@ -150,27 +164,24 @@ data &outds;
|
|||||||
/* output records that contain values other than digits and spaces */
|
/* output records that contain values other than digits and spaces */
|
||||||
if notdigit(compress(raw_value3,' '))>0 then do;
|
if notdigit(compress(raw_value3,' '))>0 then do;
|
||||||
putlog raw_value3= $hex32.;
|
putlog raw_value3= $hex32.;
|
||||||
REASON_CD='Invalid RAW_VALUE';
|
REASON_CD=cats('Invalid RAW_VALUE:',raw_value);
|
||||||
putlog REASON_CD= raw_value= raw_value1= raw_value2= raw_value3=;
|
putlog REASON_CD= raw_value= raw_value1= raw_value2= raw_value3=;
|
||||||
|
call symputx('reason_cd',reason_cd,'l');
|
||||||
|
call symputx('nobs',_n_,'l');
|
||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%local nobs;
|
|
||||||
%let nobs=0;
|
|
||||||
data _null_;
|
data _null_;
|
||||||
set &outds end=last;
|
set &outds end=last;
|
||||||
putlog (_all_)(=);
|
putlog (_all_)(=);
|
||||||
if last then do;
|
|
||||||
call symputx('REASON_CD',reason_cd,'l');
|
|
||||||
call symputx('nobs',_n_,'l');
|
|
||||||
end;
|
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%mp_abort(iftrue=(&abort=YES and &nobs>0),
|
%mp_abort(iftrue=(&abort=YES and &nobs>0),
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(&nobs filter issues in &inds, reason: &reason_cd, details in &outds)
|
msg=%str(Data issue: %superq(reason_cd))
|
||||||
)
|
)
|
||||||
|
|
||||||
%if &nobs>0 %then %do;
|
%if &nobs>0 %then %do;
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ filename &fref1 clear;
|
|||||||
run;
|
run;
|
||||||
%mp_abort(
|
%mp_abort(
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(Filter issues in &inref: %quote(&reason_cd))
|
msg=%str(Filter validation issues. ERR=%superq(SYSERRORTEXT)
|
||||||
|
, WARN=%superq(SYSWARNINGTEXT) )
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%let syscc=1008;
|
%let syscc=1008;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%put output location=&jref;
|
%put output location=&jref;
|
||||||
%if &action=OPEN %then %do;
|
%if &action=OPEN %then %do;
|
||||||
OPTIONS NOBOMFILE;
|
options nobomfile;
|
||||||
data _null_;file &jref encoding='utf-8';
|
data _null_;file &jref encoding='utf-8';
|
||||||
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
|
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
|
||||||
run;
|
run;
|
||||||
|
|||||||
@@ -9,7 +9,15 @@
|
|||||||
|
|
||||||
%mp_searchcols(libs=sashelp work, cols=name sex age)
|
%mp_searchcols(libs=sashelp work, cols=name sex age)
|
||||||
|
|
||||||
@param libs=
|
@param libs=(SASHELP) Space separated list of libraries to search for columns
|
||||||
|
@param cols= Space separated list of column names to search for (not case
|
||||||
|
sensitive)
|
||||||
|
@param outds=(mp_searchcols) the table to create with the results. Will have
|
||||||
|
one line per table match.
|
||||||
|
@param match=(ANY) The match type. Valid values:
|
||||||
|
@li ANY - The table contains at least one of the columns
|
||||||
|
@li WILD - The table contains a column with a name that partially matches
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
**/
|
**/
|
||||||
@@ -17,6 +25,7 @@
|
|||||||
%macro mp_searchcols(libs=sashelp
|
%macro mp_searchcols(libs=sashelp
|
||||||
,cols=
|
,cols=
|
||||||
,outds=mp_searchcols
|
,outds=mp_searchcols
|
||||||
|
,match=ANY
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
%put &sysmacroname process began at %sysfunc(datetime(),datetime19.);
|
%put &sysmacroname process began at %sysfunc(datetime(),datetime19.);
|
||||||
@@ -38,8 +47,10 @@ create table _data_ as
|
|||||||
%end;
|
%end;
|
||||||
order by 1,2,3;
|
order by 1,2,3;
|
||||||
|
|
||||||
|
%local tempds;
|
||||||
|
%let tempds=&syslast;
|
||||||
data &outds;
|
data &outds;
|
||||||
set &syslast;
|
set &tempds;
|
||||||
length cols matchcols $32767;
|
length cols matchcols $32767;
|
||||||
cols=upcase(symget('cols'));
|
cols=upcase(symget('cols'));
|
||||||
colcount=countw(cols);
|
colcount=countw(cols);
|
||||||
@@ -53,10 +64,29 @@ data &outds;
|
|||||||
retain matchcols;
|
retain matchcols;
|
||||||
matchcols='';
|
matchcols='';
|
||||||
end;
|
end;
|
||||||
|
%if &match=ANY %then %do;
|
||||||
if findw(cols,name,,'spit') then do;
|
if findw(cols,name,,'spit') then do;
|
||||||
sumcols+1;
|
sumcols+1;
|
||||||
matchcols=cats(matchcols)!!' '!!cats(name);
|
matchcols=cats(matchcols)!!' '!!cats(name);
|
||||||
end;
|
end;
|
||||||
|
%end;
|
||||||
|
%else %if &match=WILD %then %do;
|
||||||
|
if _n_=1 then do;
|
||||||
|
retain wcount;
|
||||||
|
wcount=countw(cols);
|
||||||
|
drop wcount;
|
||||||
|
end;
|
||||||
|
do i=1 to wcount;
|
||||||
|
length curword $32;
|
||||||
|
curword=scan(cols,i,' ');
|
||||||
|
drop curword;
|
||||||
|
if index(name,cats(curword)) then do;
|
||||||
|
sumcols+1;
|
||||||
|
matchcols=cats(matchcols)!!' '!!cats(curword);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
%end;
|
||||||
|
|
||||||
if last.memname then do;
|
if last.memname then do;
|
||||||
if sumcols>0 then output;
|
if sumcols>0 then output;
|
||||||
if sumcols=colcount then putlog "Full Match: " libname memname;
|
if sumcols=colcount then putlog "Full Match: " libname memname;
|
||||||
@@ -66,6 +96,8 @@ run;
|
|||||||
|
|
||||||
proc sort; by descending sumcols memname libname; run;
|
proc sort; by descending sumcols memname libname; run;
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
drop table &tempds;
|
||||||
%put &sysmacroname process finished at %sysfunc(datetime(),datetime19.);
|
%put &sysmacroname process finished at %sysfunc(datetime(),datetime19.);
|
||||||
|
|
||||||
%mend;
|
%mend mp_searchcols;
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
-- NOTE - THE COPYRIGHT BELOW IS IN RELATION TO THE JSON.LUA FILE ONLY
|
||||||
|
-- THIS FILE STARTS ON THE NEXT LINE AND WILL FINISH WITH "JSON.LUA ENDS HERE"
|
||||||
--
|
--
|
||||||
-- json.lua
|
-- json.lua
|
||||||
--
|
--
|
||||||
@@ -369,3 +371,5 @@ function json.decode(str)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return json
|
return json
|
||||||
|
|
||||||
|
-- JSON.LUA ENDS HERE
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
%macro ml_json();
|
%macro ml_json();
|
||||||
data _null_;
|
data _null_;
|
||||||
file "%sysfunc(pathname(work))/ml_json.lua";
|
file "%sysfunc(pathname(work))/ml_json.lua";
|
||||||
|
put '-- NOTE - THE COPYRIGHT BELOW IS IN RELATION TO THE JSON.LUA FILE ONLY ';
|
||||||
|
put '-- THIS FILE STARTS ON THE NEXT LINE AND WILL FINISH WITH "JSON.LUA ENDS HERE" ';
|
||||||
put '-- ';
|
put '-- ';
|
||||||
put '-- json.lua ';
|
put '-- json.lua ';
|
||||||
put '-- ';
|
put '-- ';
|
||||||
@@ -383,6 +385,8 @@ data _null_;
|
|||||||
put 'end ';
|
put 'end ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put 'return json ';
|
put 'return json ';
|
||||||
|
put ' ';
|
||||||
|
put '-- JSON.LUA ENDS HERE ';
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%inc "%sysfunc(pathname(work))/ml_json.lua";
|
%inc "%sysfunc(pathname(work))/ml_json.lua";
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ data _null_;
|
|||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%put output location=&jref; ';
|
put '%put output location=&jref; ';
|
||||||
put '%if &action=OPEN %then %do; ';
|
put '%if &action=OPEN %then %do; ';
|
||||||
put ' OPTIONS NOBOMFILE; ';
|
put ' options nobomfile; ';
|
||||||
put ' data _null_;file &jref encoding=''utf-8''; ';
|
put ' data _null_;file &jref encoding=''utf-8''; ';
|
||||||
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
|
|||||||
50
tests/base/mp_searchcols.test.sas
Normal file
50
tests/base/mp_searchcols.test.sas
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_searchcols.sas
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_searchcols.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
/** Test 1 - full col match */
|
||||||
|
data example1;
|
||||||
|
var1=1;
|
||||||
|
var2=2;
|
||||||
|
var3=3;
|
||||||
|
data example2;
|
||||||
|
var1=1;
|
||||||
|
var2=2;
|
||||||
|
data example3;
|
||||||
|
var2=2;
|
||||||
|
var3=3;
|
||||||
|
data example4;
|
||||||
|
matchmehere=1;
|
||||||
|
data example5;
|
||||||
|
hereyoucan_matchme_also=1;
|
||||||
|
data example6;
|
||||||
|
do_not_forget_me=1;
|
||||||
|
data example7;
|
||||||
|
we_shall_not_forget=1;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_searchcols(libs=work,cols=var1 var2,outds=testme)
|
||||||
|
|
||||||
|
%mp_assertdsobs(work.testme,
|
||||||
|
desc=Test1 - check exact variables are found,
|
||||||
|
test=EQUALS 3,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* test 2 - wildcard match */
|
||||||
|
|
||||||
|
%mp_searchcols(libs=work,cols=matchme forget,match=WILD, outds=testme2)
|
||||||
|
|
||||||
|
%mp_assertdsobs(work.testme2,
|
||||||
|
desc=Test1 - check fuzzy matches are found,
|
||||||
|
test=EQUALS 4,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
filename testref temp;
|
filename testref temp;
|
||||||
data _null_;
|
data _null_;
|
||||||
file testref;
|
file testref;
|
||||||
|
put 'data;run;';
|
||||||
put 'endsas;';
|
put 'endsas;';
|
||||||
run;
|
run;
|
||||||
%mv_createjob(
|
%mv_createjob(
|
||||||
@@ -31,7 +32,7 @@ run;
|
|||||||
%mv_jobexecute(
|
%mv_jobexecute(
|
||||||
path=&mcTestAppLoc/jobs/temp,
|
path=&mcTestAppLoc/jobs/temp,
|
||||||
name=testjob,
|
name=testjob,
|
||||||
outds=work.info,
|
outds=work.info
|
||||||
)
|
)
|
||||||
|
|
||||||
%* Wait for it to finish;
|
%* Wait for it to finish;
|
||||||
@@ -52,10 +53,15 @@ run;
|
|||||||
|
|
||||||
|
|
||||||
data _null_;
|
data _null_;
|
||||||
infile mylog;
|
infile mylog end=eof;
|
||||||
input;
|
input;
|
||||||
if index(_infile_,'endsas;') then call symputx('found',1);
|
putlog _infile_;
|
||||||
else call symputx('found',0);
|
retain found 0;
|
||||||
|
if index(_infile_,'endsas;') then do;
|
||||||
|
found=1;
|
||||||
|
call symputx('found',found);
|
||||||
|
end;
|
||||||
|
else if eof and found ne 1 then call symputx('found',0);
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%mp_assert(
|
%mp_assert(
|
||||||
|
|||||||
78
tests/viya/mv_jobflow.test.1.sas
Normal file
78
tests/viya/mv_jobflow.test.1.sas
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
@file
|
||||||
|
@brief Testing mv_jobflow macro
|
||||||
|
@details One of the remote jobs aborts with syscc>0 - test to
|
||||||
|
make sure this comes back to the calling session
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mv_createjob.sas
|
||||||
|
@li mv_jobflow.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Case 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
filename testprog temp;
|
||||||
|
data _null_;
|
||||||
|
file testprog;
|
||||||
|
put '%put this is job: &_program;'
|
||||||
|
/ '%put this was run in flow &flow_id;'
|
||||||
|
/ 'data ;'
|
||||||
|
/ ' rval=rand("uniform");'
|
||||||
|
/ ' rand=rval*¯ovar1;'
|
||||||
|
/ ' do x=1 to rand;'
|
||||||
|
/ ' y=rand*¯ovar2;'
|
||||||
|
/ ' if (rval>0.50) then abort;'
|
||||||
|
/ ' else output;'
|
||||||
|
/ ' end;'
|
||||||
|
/ 'run;'
|
||||||
|
;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mv_createjob(path=/Public/temp,name=demo1,code=testprog)
|
||||||
|
%mv_createjob(path=/Public/temp,name=demo2,code=testprog)
|
||||||
|
|
||||||
|
data work.inputjobs;
|
||||||
|
_contextName='SAS Job Execution compute context';
|
||||||
|
do flow_id=1 to 2;
|
||||||
|
do i=1 to 4;
|
||||||
|
_program='/Public/temp/demo1';
|
||||||
|
macrovar1=10*i;
|
||||||
|
macrovar2=4*i;
|
||||||
|
output;
|
||||||
|
i+1;
|
||||||
|
_program='/Public/temp/demo2';
|
||||||
|
macrovar1=40*i;
|
||||||
|
macrovar2=44*i;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
* Trigger the flow ;
|
||||||
|
|
||||||
|
%put NOTE: &=syscc;
|
||||||
|
|
||||||
|
%mv_jobflow(inds=work.inputjobs
|
||||||
|
,maxconcurrency=2
|
||||||
|
,outds=work.results
|
||||||
|
,outref=myjoblog
|
||||||
|
,raise_err=1
|
||||||
|
,mdebug=1
|
||||||
|
)
|
||||||
|
|
||||||
|
%put NOTE: &=syscc;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile myjoblog;
|
||||||
|
input; put _infile_;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc ne 0),
|
||||||
|
desc=Check that non zero return code is returned if called job fails
|
||||||
|
)
|
||||||
74
tests/viya/mv_jobflow.test.2.sas
Normal file
74
tests/viya/mv_jobflow.test.2.sas
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mv_jobflow macro
|
||||||
|
@details All jobs complete successfully with syscc = 0 - test to
|
||||||
|
make sure this comes back to the calling session
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mv_createjob.sas
|
||||||
|
@li mv_jobflow.sas
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Case 1
|
||||||
|
*/
|
||||||
|
filename testprog temp;
|
||||||
|
data _null_;
|
||||||
|
file testprog;
|
||||||
|
put '%put this is job: &_program;'
|
||||||
|
/ '%put this was run in flow &flow_id;'
|
||||||
|
/ 'data ;'
|
||||||
|
/ ' rval=rand("uniform");'
|
||||||
|
/ ' rand=rval*¯ovar1;'
|
||||||
|
/ ' do x=1 to rand;'
|
||||||
|
/ ' y=rand*¯ovar2;'
|
||||||
|
/ ' output;'
|
||||||
|
/ ' end;'
|
||||||
|
/ 'run;'
|
||||||
|
;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mv_createjob(path=/Public/temp,name=demo1,code=testprog)
|
||||||
|
%mv_createjob(path=/Public/temp,name=demo2,code=testprog)
|
||||||
|
|
||||||
|
data work.inputjobs;
|
||||||
|
_contextName='SAS Job Execution compute context';
|
||||||
|
do flow_id=1 to 2;
|
||||||
|
do i=1 to 4;
|
||||||
|
_program='/Public/temp/demo1';
|
||||||
|
macrovar1=10*i;
|
||||||
|
macrovar2=4*i;
|
||||||
|
output;
|
||||||
|
i+1;
|
||||||
|
_program='/Public/temp/demo2';
|
||||||
|
macrovar1=40*i;
|
||||||
|
macrovar2=44*i;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
* Trigger the flow ;
|
||||||
|
|
||||||
|
%put NOTE: &=syscc;
|
||||||
|
|
||||||
|
%mv_jobflow(inds=work.inputjobs
|
||||||
|
,maxconcurrency=2
|
||||||
|
,outds=work.results
|
||||||
|
,outref=myjoblog
|
||||||
|
,raise_err=1
|
||||||
|
,mdebug=1
|
||||||
|
)
|
||||||
|
|
||||||
|
%put NOTE: &=syscc;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile myjoblog;
|
||||||
|
input; put _infile_;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc eq 0),
|
||||||
|
desc=Check that a zero return code is returned if no called job fails
|
||||||
|
)
|
||||||
@@ -241,7 +241,7 @@ data _null_;
|
|||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%put output location=&jref; ';
|
put '%put output location=&jref; ';
|
||||||
put '%if &action=OPEN %then %do; ';
|
put '%if &action=OPEN %then %do; ';
|
||||||
put ' OPTIONS NOBOMFILE; ';
|
put ' options nobomfile; ';
|
||||||
put ' data _null_;file &jref encoding=''utf-8''; ';
|
put ' data _null_;file &jref encoding=''utf-8''; ';
|
||||||
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
put ' put ''{"START_DTTM" : "'' "%sysfunc(datetime(),datetime20.3)" ''"''; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
|
|||||||
@@ -97,8 +97,8 @@
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access
|
@param [in] access_token_var= The global macro variable to contain the
|
||||||
token
|
access token
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
@li password
|
@li password
|
||||||
@li authorization_code
|
@li authorization_code
|
||||||
@@ -237,123 +237,143 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
|
|
||||||
/* start loop */
|
/* start loop */
|
||||||
%do fid=1 %to &flowcnt;
|
%do fid=1 %to &flowcnt;
|
||||||
%put preparing job attributes for flow &&flow&fid;
|
|
||||||
%local jds jcnt;
|
|
||||||
data &jds(drop=_contextName _program);
|
|
||||||
set &inds(where=(flow_id=&&flow&fid));
|
|
||||||
if _contextName='' then _contextName="SAS Job Execution compute context";
|
|
||||||
call symputx(cats('job',_n_),_program,'l');
|
|
||||||
call symputx(cats('context',_n_),_contextName,'l');
|
|
||||||
call symputx('jcnt',_n_,'l');
|
|
||||||
run;
|
|
||||||
%put exporting job variables in json format;
|
|
||||||
%do jid=1 %to &jcnt;
|
|
||||||
data &jjson;
|
|
||||||
set &jds;
|
|
||||||
if _n_=&jid then do;
|
|
||||||
output;
|
|
||||||
stop;
|
|
||||||
end;
|
|
||||||
run;
|
|
||||||
proc json out=&jfref;
|
|
||||||
export &jjson / nosastags fmtnumeric;
|
|
||||||
run;
|
|
||||||
data _null_;
|
|
||||||
infile &jfref lrecl=32767;
|
|
||||||
input;
|
|
||||||
jparams='jparams'!!left(symget('jid'));
|
|
||||||
call symputx(jparams,substr(_infile_,3,length(_infile_)-4));
|
|
||||||
run;
|
|
||||||
%local jobuid&jid;
|
|
||||||
%let jobuid&jid=0; /* used in next loop */
|
|
||||||
%end;
|
|
||||||
%local concurrency completed;
|
|
||||||
%let concurrency=0;
|
|
||||||
%let completed=0;
|
|
||||||
proc sql; drop table &jdsrunning;
|
|
||||||
%do jid=1 %to &jcnt;
|
|
||||||
/**
|
|
||||||
* now we can execute the jobs up to the maxconcurrency setting
|
|
||||||
*/
|
|
||||||
%if "&&job&jid" ne "0" %then %do; /* this var is zero if job finished */
|
|
||||||
|
|
||||||
/* check to see if the job finished in the previous round */
|
%if not ( &raise_err and &syscc ) %then %do;
|
||||||
%if %sysfunc(exist(&outds))=1 %then %do;
|
|
||||||
%local jobcheck; %let jobcheck=0;
|
%put preparing job attributes for flow &&flow&fid;
|
||||||
proc sql noprint;
|
%local jds jcnt;
|
||||||
select count(*) into: jobcheck
|
data &jds(drop=_contextName _program);
|
||||||
from &outds where uuid="&&jobuid&jid";
|
set &inds(where=(flow_id=&&flow&fid));
|
||||||
%if &jobcheck>0 %then %do;
|
if _contextName='' then _contextName="SAS Job Execution compute context";
|
||||||
%put &&job&jid in flow &fid with uid &&jobuid&jid completed!;
|
call symputx(cats('job',_n_),_program,'l');
|
||||||
%let job&jid=0;
|
call symputx(cats('context',_n_),_contextName,'l');
|
||||||
|
call symputx('jcnt',_n_,'l');
|
||||||
|
run;
|
||||||
|
%put exporting job variables in json format;
|
||||||
|
%do jid=1 %to &jcnt;
|
||||||
|
data &jjson;
|
||||||
|
set &jds;
|
||||||
|
if _n_=&jid then do;
|
||||||
|
output;
|
||||||
|
stop;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
proc json out=&jfref;
|
||||||
|
export &jjson / nosastags fmtnumeric;
|
||||||
|
run;
|
||||||
|
data _null_;
|
||||||
|
infile &jfref lrecl=32767;
|
||||||
|
input;
|
||||||
|
jparams='jparams'!!left(symget('jid'));
|
||||||
|
call symputx(jparams,substr(_infile_,3,length(_infile_)-4));
|
||||||
|
run;
|
||||||
|
%local jobuid&jid;
|
||||||
|
%let jobuid&jid=0; /* used in next loop */
|
||||||
|
%end;
|
||||||
|
%local concurrency completed;
|
||||||
|
%let concurrency=0;
|
||||||
|
%let completed=0;
|
||||||
|
proc sql; drop table &jdsrunning;
|
||||||
|
%do jid=1 %to &jcnt;
|
||||||
|
/**
|
||||||
|
* now we can execute the jobs up to the maxconcurrency setting
|
||||||
|
*/
|
||||||
|
%if "&&job&jid" ne "0" %then %do; /* this var is zero if job finished */
|
||||||
|
|
||||||
|
/* check to see if the job finished in the previous round */
|
||||||
|
%if %sysfunc(exist(&outds))=1 %then %do;
|
||||||
|
%local jobcheck; %let jobcheck=0;
|
||||||
|
proc sql noprint;
|
||||||
|
select count(*) into: jobcheck
|
||||||
|
from &outds where uuid="&&jobuid&jid";
|
||||||
|
%if &jobcheck>0 %then %do;
|
||||||
|
%put &&job&jid in flow &fid with uid &&jobuid&jid completed!;
|
||||||
|
%let job&jid=0;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* check if job was triggered and, if
|
||||||
|
so, if we have enough slots to run? */
|
||||||
|
%if ("&&jobuid&jid"="0") and (&concurrency<&maxconcurrency) %then %do;
|
||||||
|
|
||||||
|
/* But only start if no issues detected so far */
|
||||||
|
%if not ( &raise_err and &syscc ) %then %do;
|
||||||
|
|
||||||
|
%local jobname jobpath;
|
||||||
|
%let jobname=%scan(&&job&jid,-1,/);
|
||||||
|
%let jobpath=
|
||||||
|
%substr(&&job&jid,1,%length(&&job&jid)-%length(&jobname)-1);
|
||||||
|
|
||||||
|
%put executing &jobpath/&jobname with paramstring &&jparams&jid;
|
||||||
|
%mv_jobexecute(path=&jobpath
|
||||||
|
,name=&jobname
|
||||||
|
,paramstring=%superq(jparams&jid)
|
||||||
|
,outds=&jdsapp
|
||||||
|
)
|
||||||
|
data &jdsapp;
|
||||||
|
format jobparams $32767.;
|
||||||
|
set &jdsapp(where=(method='GET' and rel='state'));
|
||||||
|
jobparams=symget("jparams&jid");
|
||||||
|
/* uri here has the /state suffix */
|
||||||
|
uuid=scan(uri,-2,'/');
|
||||||
|
call symputx("jobuid&jid",uuid,'l');
|
||||||
|
run;
|
||||||
|
proc append base=&jdsrunning data=&jdsapp;
|
||||||
|
run;
|
||||||
|
%let concurrency=%eval(&concurrency+1);
|
||||||
|
/* sleep one second after every request to smooth the impact */
|
||||||
|
data _null_;
|
||||||
|
call sleep(1,1);
|
||||||
|
run;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do; /* Job was skipped due to problems */
|
||||||
|
|
||||||
|
%put jobid &&job&jid in flow &fid skipped due to SYSCC (&syscc);
|
||||||
|
%let completed = %eval(&completed+1);
|
||||||
|
%let job&jid=0; /* Indicate job has finished */
|
||||||
|
|
||||||
|
%end;
|
||||||
|
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
|
%if &jid=&jcnt %then %do;
|
||||||
|
/* we are at the end of the loop - check which jobs have finished */
|
||||||
|
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref
|
||||||
|
,raise_err=&raise_err,mdebug=&mdebug)
|
||||||
|
%local done;
|
||||||
|
%let done=%mf_nobs(&jdswaitfor);
|
||||||
|
%if &done>0 %then %do;
|
||||||
|
%let completed=%eval(&completed+&done);
|
||||||
|
%let concurrency=%eval(&concurrency-&done);
|
||||||
|
data &jdsapp;
|
||||||
|
set &jdswaitfor;
|
||||||
|
flow_id=&&flow&fid;
|
||||||
|
uuid=scan(uri,-1,'/');
|
||||||
|
run;
|
||||||
|
proc append base=&outds data=&jdsapp;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
proc sql;
|
||||||
|
delete from &jdsrunning
|
||||||
|
where uuid in (select uuid from &outds
|
||||||
|
where state in ('canceled','completed','failed')
|
||||||
|
);
|
||||||
|
|
||||||
/* check if job was triggered and if so, if we have enough slots to run */
|
/* loop again if jobs are left */
|
||||||
%if "&&jobuid&jid"="0" and &concurrency<&maxconcurrency %then %do;
|
%if &completed < &jcnt %then %do;
|
||||||
%local jobname jobpath;
|
%let jid=0;
|
||||||
%let jobname=%scan(&&job&jid,-1,/);
|
%put looping flow &fid again;
|
||||||
%let jobpath=
|
%put &completed of &jcnt jobs completed, &concurrency jobs running;
|
||||||
%substr(&&job&jid,1,%length(&&job&jid)-%length(&jobname)-1);
|
%end;
|
||||||
%put executing &jobpath/&jobname with paramstring &&jparams&jid;
|
|
||||||
%mv_jobexecute(path=&jobpath
|
|
||||||
,name=&jobname
|
|
||||||
,paramstring=%superq(jparams&jid)
|
|
||||||
,outds=&jdsapp
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
data &jdsapp;
|
|
||||||
format jobparams $32767.;
|
|
||||||
set &jdsapp(where=(method='GET' and rel='state'));
|
|
||||||
jobparams=symget("jparams&jid");
|
|
||||||
/* uri here has the /state suffix */
|
|
||||||
uuid=scan(uri,-2,'/');
|
|
||||||
call symputx("jobuid&jid",uuid,'l');
|
|
||||||
run;
|
|
||||||
proc append base=&jdsrunning data=&jdsapp;
|
|
||||||
run;
|
|
||||||
%let concurrency=%eval(&concurrency+1);
|
|
||||||
/* sleep one second after every request to smooth the impact */
|
|
||||||
data _null_;
|
|
||||||
call sleep(1,1);
|
|
||||||
run;
|
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%if &jid=&jcnt %then %do;
|
|
||||||
/* we are at the end of the loop - time to see which jobs have finished */
|
|
||||||
%mv_jobwaitfor(ANY
|
|
||||||
,inds=&jdsrunning
|
|
||||||
,outds=&jdswaitfor
|
|
||||||
,outref=&outref
|
|
||||||
,raise_err=&raise_err
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
%local done;
|
|
||||||
%let done=%mf_nobs(&jdswaitfor);
|
|
||||||
%if &done>0 %then %do;
|
|
||||||
%let completed=%eval(&completed+&done);
|
|
||||||
%let concurrency=%eval(&concurrency-&done);
|
|
||||||
data &jdsapp;
|
|
||||||
set &jdswaitfor;
|
|
||||||
flow_id=&&flow&fid;
|
|
||||||
uuid=scan(uri,-1,'/');
|
|
||||||
run;
|
|
||||||
proc append base=&outds data=&jdsapp;
|
|
||||||
run;
|
|
||||||
%end;
|
|
||||||
proc sql;
|
|
||||||
delete from &jdsrunning
|
|
||||||
where uuid in (select uuid from &outds
|
|
||||||
where state in ('canceled','completed','failed')
|
|
||||||
);
|
|
||||||
|
|
||||||
/* loop again if jobs are left */
|
%end;
|
||||||
%if &completed < &jcnt %then %do;
|
%else %do;
|
||||||
%let jid=0;
|
|
||||||
%put looping flow &fid again - &completed of &jcnt jobs completed,
|
%put Flow &&flow&fid skipped due to SYSCC (&syscc);
|
||||||
&concurrency jobs running;
|
|
||||||
%end;
|
|
||||||
%end;
|
|
||||||
%end;
|
%end;
|
||||||
/* back up and execute the next flow */
|
/* back up and execute the next flow */
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
Reference in New Issue
Block a user