mirror of
https://github.com/sasjs/core.git
synced 2025-12-12 06:54:35 +00:00
Compare commits
38 Commits
v2.17.1
...
testframew
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e564b5409 | ||
|
|
298acc4e50 | ||
|
|
af98909753 | ||
|
|
b9d33b38bf | ||
|
|
b61b5f1856 | ||
|
|
805474bb46 | ||
|
|
61701f3c6a | ||
|
|
f20d7476bf | ||
|
|
04a3189a89 | ||
|
|
b1380983ec | ||
|
|
b4834f9b40 | ||
|
|
1b5ad93cad | ||
|
|
f2942f2032 | ||
|
|
4198448b81 | ||
|
|
47a33452e0 | ||
|
|
fb21a0adfd | ||
|
|
e01b06b640 | ||
|
|
24380ddf26 | ||
|
|
1ef42d45af | ||
|
|
6ee13a2779 | ||
|
|
ffd2e135dc | ||
|
|
7f2ad5fc66 | ||
| ff1eb54cc3 | |||
|
|
d6235c6357 | ||
|
|
98118adb9a | ||
|
|
369c4412f3 | ||
|
|
7d7608f06c | ||
|
|
3791cb8a2c | ||
|
|
ff82f7d75c | ||
|
|
fdd566e8ce | ||
|
|
328f8c260b | ||
|
|
029169ac80 | ||
| 66ff1de7a9 | |||
| 053290c7df | |||
| af71a5e53b | |||
| ecdce86287 | |||
| ba1272aaf7 | |||
| d6056b9397 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,9 +1,13 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
sasjsbuild/
|
sasjsbuild/
|
||||||
|
sasjsresults/
|
||||||
|
|
||||||
# avoid filenames with spaces being committed to source control
|
# avoid filenames with spaces being committed to source control
|
||||||
**\ **
|
**\ **
|
||||||
|
|
||||||
# ignore the mc_* files - containing macros for individual libraries
|
# ignore the mc_* files - containing macros for individual libraries
|
||||||
mc_*
|
mc_*
|
||||||
|
|
||||||
|
# ignore .env files as they can contain sasjs access tokens
|
||||||
|
*.env*
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
@details Returns 0 if ANY of the variables do not exist, or 1 if they ALL do.
|
@details Returns 0 if ANY of the variables do not exist, or 1 if they ALL do.
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%put %mf_existVarList(sashelp.class, age sex name dummyvar)
|
%put %mf_existVarList(sashelp.class, age sex name dummyvar);
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_abort.sas
|
@li mf_abort.sas
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
%let dsid=%sysfunc(open(&libds,is));
|
%let dsid=%sysfunc(open(&libds,is));
|
||||||
|
|
||||||
%if &dsid=0 %then %do;
|
%if &dsid=0 %then %do;
|
||||||
%put WARNING: unable to open &libds in mf_existvarlist (&dsid);
|
%put %str(WARN)ING: unable to open &libds in mf_existvarlist (&dsid);
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if %sysfunc(attrn(&dsid,NVARS))=0 %then %do;
|
%if %sysfunc(attrn(&dsid,NVARS))=0 %then %do;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
%local dsid rc;
|
%local dsid rc;
|
||||||
%let dsid=%sysfunc(open(&libds,is));
|
%let dsid=%sysfunc(open(&libds,is));
|
||||||
%if &dsid = 0 %then %do;
|
%if &dsid = 0 %then %do;
|
||||||
%put WARNING: Cannot open %trim(&libds), system message below;
|
%put %str(WARN)ING: Cannot open %trim(&libds), system message below;
|
||||||
%put %sysfunc(sysmsg());
|
%put %sysfunc(sysmsg());
|
||||||
-1
|
-1
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mf_getxengine.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
/** @cond */
|
/** @cond */
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,9 @@
|
|||||||
8.
|
8.
|
||||||
NOTE: Variable renegade does not exist in test
|
NOTE: Variable renegade does not exist in test
|
||||||
|
|
||||||
@param libds Two part dataset (or view) reference.
|
@param [in] libds Two part dataset (or view) reference.
|
||||||
@param var Variable name for which a format should be returned
|
@param [in] var Variable name for which a format should be returned
|
||||||
@param force Set to 1 to supply a default if the variable has no format
|
@param [in] force=(0) Set to 1 to supply a default if the variable has no format
|
||||||
@returns outputs format
|
@returns outputs format
|
||||||
|
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
%let vlen = %sysfunc(varlen(&dsid, &vnum));
|
%let vlen = %sysfunc(varlen(&dsid, &vnum));
|
||||||
%let vtype = %sysfunc(vartype(&dsid, &vnum.));
|
%let vtype = %sysfunc(vartype(&dsid, &vnum.));
|
||||||
%if &vtype=C %then %let vformat=$&vlen..;
|
%if &vtype=C %then %let vformat=$&vlen..;
|
||||||
%else %let vformat=8.;
|
%else %let vformat=best.;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|
||||||
@@ -68,4 +68,4 @@
|
|||||||
%let rc = %sysfunc(close(&dsid));
|
%let rc = %sysfunc(close(&dsid));
|
||||||
/* Return variable format */
|
/* Return variable format */
|
||||||
&vformat
|
&vformat
|
||||||
%mend;
|
%mend mf_getVarFormat;
|
||||||
@@ -10,14 +10,21 @@
|
|||||||
returns:
|
returns:
|
||||||
> List of Variables=Name Sex Age Height Weight
|
> List of Variables=Name Sex Age Height Weight
|
||||||
|
|
||||||
|
For a seperated list of column values:
|
||||||
|
|
||||||
%put %mf_getvarlist(sashelp.class,dlm=%str(,),quote=double);
|
%put %mf_getvarlist(sashelp.class,dlm=%str(,),quote=double);
|
||||||
|
|
||||||
returns:
|
returns:
|
||||||
> "Name","Sex","Age","Height","Weight"
|
> "Name","Sex","Age","Height","Weight"
|
||||||
|
|
||||||
@param libds Two part dataset (or view) reference.
|
@param [in] libds Two part dataset (or view) reference.
|
||||||
@param dlm= provide a delimiter (eg comma or space) to separate the vars
|
@param [in] dlm= ( ) Provide a delimiter (eg comma or space) to separate the
|
||||||
@param quote= use either DOUBLE or SINGLE to quote the results
|
variables
|
||||||
|
@param [in] quote= (none) use either DOUBLE or SINGLE to quote the results
|
||||||
|
@param [in] typefilter= (A) Filter for certain types of column. Valid values:
|
||||||
|
@li A Return All columns
|
||||||
|
@li C Return Character columns
|
||||||
|
@li N Return Numeric columns
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@@ -27,9 +34,10 @@
|
|||||||
%macro mf_getvarlist(libds
|
%macro mf_getvarlist(libds
|
||||||
,dlm=%str( )
|
,dlm=%str( )
|
||||||
,quote=no
|
,quote=no
|
||||||
|
,typefilter=A
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
/* declare local vars */
|
/* declare local vars */
|
||||||
%local outvar dsid nvars x rc dlm q var;
|
%local outvar dsid nvars x rc dlm q var vtype;
|
||||||
|
|
||||||
/* credit Rowland Hale - byte34 is double quote, 39 is single quote */
|
/* credit Rowland Hale - byte34 is double quote, 39 is single quote */
|
||||||
%if %upcase("e)=DOUBLE %then %let q=%qsysfunc(byte(34));
|
%if %upcase("e)=DOUBLE %then %let q=%qsysfunc(byte(34));
|
||||||
@@ -37,23 +45,24 @@
|
|||||||
/* open dataset in macro */
|
/* open dataset in macro */
|
||||||
%let dsid=%sysfunc(open(&libds));
|
%let dsid=%sysfunc(open(&libds));
|
||||||
|
|
||||||
|
|
||||||
%if &dsid %then %do;
|
%if &dsid %then %do;
|
||||||
%let nvars=%sysfunc(attrn(&dsid,NVARS));
|
%let nvars=%sysfunc(attrn(&dsid,NVARS));
|
||||||
%if &nvars>0 %then %do;
|
%if &nvars>0 %then %do;
|
||||||
/* add first dataset variable to global macro variable */
|
/* add variables with supplied delimeter */
|
||||||
%let outvar=&q.%sysfunc(varname(&dsid,1))&q.;
|
|
||||||
/* add remaining variables with supplied delimeter */
|
|
||||||
%do x=1 %to &nvars;
|
%do x=1 %to &nvars;
|
||||||
|
/* get variable type */
|
||||||
|
%let vtype=%sysfunc(vartype(&dsid,&x));
|
||||||
|
%if &vtype=&typefilter or &typefilter=A %then %do;
|
||||||
%let var=&q.%sysfunc(varname(&dsid,&x))&q.;
|
%let var=&q.%sysfunc(varname(&dsid,&x))&q.;
|
||||||
%if &var=&q&q %then %do;
|
%if &var=&q&q %then %do;
|
||||||
%put &sysmacroname: Empty column found in &libds!;
|
%put &sysmacroname: Empty column found in &libds!;
|
||||||
%let var=&q. &q.;
|
%let var=&q. &q.;
|
||||||
%end;
|
%end;
|
||||||
%if &x=1 %then %let outvar=&var;
|
%if %quote(&outvar)=%quote() %then %let outvar=&var;
|
||||||
%else %let outvar=&outvar.&dlm.&var.;
|
%else %let outvar=&outvar.&dlm.&var.;
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
|
%end;
|
||||||
%let rc=%sysfunc(close(&dsid));
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
@@ -61,4 +70,4 @@
|
|||||||
%let rc=%sysfunc(close(&dsid));
|
%let rc=%sysfunc(close(&dsid));
|
||||||
%end;
|
%end;
|
||||||
&outvar
|
&outvar
|
||||||
%mend;
|
%mend mf_getvarlist;
|
||||||
@@ -45,4 +45,4 @@ Usage:
|
|||||||
%let rc = %sysfunc(close(&dsid));
|
%let rc = %sysfunc(close(&dsid));
|
||||||
/* Return variable type */
|
/* Return variable type */
|
||||||
&vtype
|
&vtype
|
||||||
%mend;
|
%mend mf_getvartype;
|
||||||
43
base/mf_getxengine.sas
Normal file
43
base/mf_getxengine.sas
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Returns the engine type of a SAS fileref
|
||||||
|
@details Queries sashelp.vextfl to get the xengine value.
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
filename feng temp;
|
||||||
|
%put %mf_getxengine(feng);
|
||||||
|
|
||||||
|
returns:
|
||||||
|
> TEMP
|
||||||
|
|
||||||
|
@param fref The fileref to check
|
||||||
|
|
||||||
|
@returns The XENGINE value in sashelp.vextfl or 0 if not found.
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mf_getengine.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mf_getxengine(fref
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
%local dsid engnum rc engine;
|
||||||
|
|
||||||
|
%let dsid=%sysfunc(
|
||||||
|
open(sashelp.vextfl(where=(fileref="%upcase(&fref)")),i)
|
||||||
|
);
|
||||||
|
%if (&dsid ^= 0) %then %do;
|
||||||
|
%let engnum=%sysfunc(varnum(&dsid,XENGINE));
|
||||||
|
%let rc=%sysfunc(fetch(&dsid));
|
||||||
|
%let engine=%sysfunc(getvarc(&dsid,&engnum));
|
||||||
|
%* put &fref. ENGINE is &engine.;
|
||||||
|
%let rc= %sysfunc(close(&dsid));
|
||||||
|
%end;
|
||||||
|
%else %let engine=0;
|
||||||
|
|
||||||
|
&engine
|
||||||
|
|
||||||
|
%mend;
|
||||||
@@ -18,4 +18,4 @@
|
|||||||
|
|
||||||
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
||||||
|
|
||||||
%mend;
|
%mend mf_uid;
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
%local count_base count_extr i i2 extr_word base_word match outvar;
|
%local count_base count_extr i i2 extr_word base_word match outvar;
|
||||||
%if %length(&str1)=0 or %length(&str2)=0 %then %do;
|
%if %length(&str1)=0 or %length(&str2)=0 %then %do;
|
||||||
%put WARNING: empty string provided!;
|
%put %str(WARN)ING: empty string provided!;
|
||||||
%put base string (str1)= &str1;
|
%put base string (str1)= &str1;
|
||||||
%put compare string (str2) = &str2;
|
%put compare string (str2) = &str2;
|
||||||
%return;
|
%return;
|
||||||
|
|||||||
56
base/mp_assert.sas
Normal file
56
base/mp_assert.sas
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Generic assertion
|
||||||
|
@details Useful in the context of writing sasjs tests. The results of the
|
||||||
|
test are _appended_ to the &outds. table.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
%mp_assert(iftrue=(1=1),
|
||||||
|
desc=Obviously true
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assert(iftrue=(1=0),
|
||||||
|
desc=Will fail
|
||||||
|
)
|
||||||
|
|
||||||
|
@param [in] iftrue= (1=1) A condition where, if true, the test is a PASS.
|
||||||
|
Else, the test is a fail.
|
||||||
|
|
||||||
|
@param [in] desc= (Testing observations) The user provided test description
|
||||||
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|
|---|---|---|
|
||||||
|
|User Provided description|PASS|Column &inds contained ALL columns|
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_assert(iftrue=(1=1),
|
||||||
|
desc=0,
|
||||||
|
outds=work.test_results
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
data ;
|
||||||
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
|
test_description=symget('desc');
|
||||||
|
test_comments="&sysmacroname: Test result of "!!symget('iftrue');
|
||||||
|
%if %eval(%unquote(&iftrue)) %then %do;
|
||||||
|
test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
test_result='FAIL';
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%local ds ;
|
||||||
|
%let ds=&syslast;
|
||||||
|
proc append base=&outds data=&ds;
|
||||||
|
run;
|
||||||
|
proc sql;
|
||||||
|
drop table &ds;
|
||||||
|
|
||||||
|
%mend mp_assert;
|
||||||
145
base/mp_assertcols.sas
Normal file
145
base/mp_assertcols.sas
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Asserts the existence (or not) of columns
|
||||||
|
@details Useful in the context of writing sasjs tests. The results of the
|
||||||
|
test are _appended_ to the &outds. table.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
%mp_assertcols(sashelp.class,
|
||||||
|
cols=name age sex,
|
||||||
|
test=ALL,
|
||||||
|
desc=check all columns exist
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assertcols(sashelp.class,
|
||||||
|
cols=a b c,
|
||||||
|
test=NONE
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assertcols(sashelp.class,
|
||||||
|
cols=age depth,
|
||||||
|
test=ANY
|
||||||
|
)
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_existds.sas
|
||||||
|
@li mf_existvarlist.sas
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
@li mf_wordsinstr1butnotstr2.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
|
||||||
|
@param [in] inds The input library.dataset to test for values
|
||||||
|
@param [in] cols= The list of columns to check for
|
||||||
|
@param [in] desc= (Testing observations) The user provided test description
|
||||||
|
@param [in] test= (ALL) The test to apply. Valid values are:
|
||||||
|
@li ALL - Test is a PASS if ALL columns exist in &inds
|
||||||
|
@li ANY - Test is a PASS if ANY of the columns exist in &inds
|
||||||
|
@li NONE - Test is a PASS if NONE of the columns exist in &inds
|
||||||
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|
|---|---|---|
|
||||||
|
|User Provided description|PASS|Column &inds contained ALL columns|
|
||||||
|
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
@li mp_assertcolvals.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_assertcols(inds,
|
||||||
|
cols=0,
|
||||||
|
test=ALL,
|
||||||
|
desc=0,
|
||||||
|
outds=work.test_results
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc - on macro entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
%local lib ds ;
|
||||||
|
%let lib=%scan(&inds,1,%str(.));
|
||||||
|
%let ds=%scan(&inds,2,%str(.));
|
||||||
|
%let cols=%upcase(&cols);
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (%mf_existds(&lib..&ds)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&lib..&ds not found!)
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&cols=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(No cols provided)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
%let test=%upcase(&test);
|
||||||
|
|
||||||
|
%if &test ne ANY and &test ne ALL and &test ne NONE %then %do;
|
||||||
|
%mp_abort(
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(Invalid test - &test)
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* now do the actual test!
|
||||||
|
*/
|
||||||
|
%local result;
|
||||||
|
%if %mf_existVarList(&inds,&cols)=1 %then %let result=ALL;
|
||||||
|
%else %do;
|
||||||
|
%local targetcols compare;
|
||||||
|
%let targetcols=%upcase(%mf_getvarlist(&inds));
|
||||||
|
%let compare=%mf_wordsinstr1butnotstr2(
|
||||||
|
Str1=&cols,
|
||||||
|
Str2=&targetcols
|
||||||
|
);
|
||||||
|
%if %cmpres(&compare)=%cmpres(&cols) %then %let result=NONE;
|
||||||
|
%else %let result=SOME;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
data;
|
||||||
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
|
test_description=symget('desc');
|
||||||
|
if test_description='0'
|
||||||
|
then test_description="Testing &inds for existence of &test of: &cols";
|
||||||
|
|
||||||
|
test_result='FAIL';
|
||||||
|
test_comments="&sysmacroname: &inds has &result columns ";
|
||||||
|
%if &test=ALL %then %do;
|
||||||
|
%if &result=ALL %then %do;
|
||||||
|
test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %if &test=ANY %then %do;
|
||||||
|
%if &result=SOME %then %do;
|
||||||
|
test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %if &test=NONE %then %do;
|
||||||
|
%if &result=NONE %then %do;
|
||||||
|
test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%local ds;
|
||||||
|
%let ds=&syslast;
|
||||||
|
proc append base=&outds data=&ds;
|
||||||
|
run;
|
||||||
|
proc sql;
|
||||||
|
drop table &ds;
|
||||||
|
|
||||||
|
%mend;
|
||||||
147
base/mp_assertcolvals.sas
Normal file
147
base/mp_assertcolvals.sas
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Asserts the values in a column
|
||||||
|
@details Useful in the context of writing sasjs tests. The results of the
|
||||||
|
test are _appended_ to the &outds. table.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
data work.checkds;
|
||||||
|
do checkval='Jane','James','Jill';
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
%mp_assertcolvals(sashelp.class.name,
|
||||||
|
checkvals=work.checkds.checkval,
|
||||||
|
desc=At least one value has a match,
|
||||||
|
test=ANYVAL
|
||||||
|
)
|
||||||
|
|
||||||
|
data work.check;
|
||||||
|
do val='M','F';
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
%mp_assertcolvals(sashelp.class.sex,
|
||||||
|
checkvals=work.check.val,
|
||||||
|
desc=All values have a match,
|
||||||
|
test=ALLVALS
|
||||||
|
)
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_existds.sas
|
||||||
|
@li mf_nobs.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
|
||||||
|
@param [in] indscol The input library.dataset.column to test for values
|
||||||
|
@param [in] checkvals= A library.dataset.column value containing a UNIQUE
|
||||||
|
list of values to be compared against the source (indscol).
|
||||||
|
@param [in] desc= (Testing observations) The user provided test description
|
||||||
|
@param [in] test= (ALLVALS) The test to apply. Valid values are:
|
||||||
|
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
|
||||||
|
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
|
||||||
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|
|---|---|---|
|
||||||
|
|User Provided description|PASS|Column &indscol contained ALL target vals|
|
||||||
|
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_assertcolvals(indscol,
|
||||||
|
checkvals=0,
|
||||||
|
test=ALLVALS,
|
||||||
|
desc=mp_assertcolvals - no desc provided,
|
||||||
|
outds=work.test_results
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc - on macro entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
%local lib ds col clib cds ccol nobs;
|
||||||
|
%let lib=%scan(&indscol,1,%str(.));
|
||||||
|
%let ds=%scan(&indscol,2,%str(.));
|
||||||
|
%let col=%scan(&indscol,3,%str(.));
|
||||||
|
%mp_abort(iftrue= (%mf_existds(&lib..&ds)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&lib..&ds not found!)
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&checkvals=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Set CHECKVALS to a library.dataset.column containing check vals)
|
||||||
|
)
|
||||||
|
%let clib=%scan(&checkvals,1,%str(.));
|
||||||
|
%let cds=%scan(&checkvals,2,%str(.));
|
||||||
|
%let ccol=%scan(&checkvals,3,%str(.));
|
||||||
|
%mp_abort(iftrue= (%mf_existds(&clib..&cds)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&clib..&cds not found!)
|
||||||
|
)
|
||||||
|
%let nobs=%mf_nobs(&clib..&cds);
|
||||||
|
%mp_abort(iftrue= (&nobs=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&clib..&cds is empty!)
|
||||||
|
)
|
||||||
|
|
||||||
|
%let test=%upcase(&test);
|
||||||
|
|
||||||
|
%if &test ne ALLVALS and &test ne ANYVAL %then %do;
|
||||||
|
%mp_abort(
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(Invalid test - &test)
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%local result orig;
|
||||||
|
%let result=-1;
|
||||||
|
%let orig=-1;
|
||||||
|
proc sql noprint;
|
||||||
|
select count(*) into: result
|
||||||
|
from &lib..&ds
|
||||||
|
where &col not in (
|
||||||
|
select &ccol from &clib..&cds
|
||||||
|
);
|
||||||
|
select count(*) into: orig from &lib..&ds;
|
||||||
|
quit;
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc after macro query)
|
||||||
|
)
|
||||||
|
|
||||||
|
data;
|
||||||
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
|
test_description=symget('desc');
|
||||||
|
test_result='FAIL';
|
||||||
|
test_comments="&sysmacroname: &lib..&ds..&col has &result values "
|
||||||
|
!!"not in &clib..&cds..&ccol ";
|
||||||
|
%if &test=ANYVAL %then %do;
|
||||||
|
if &result < &orig then test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %if &test=ALLVALS %then %do;
|
||||||
|
if &result=0 then test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%local ds;
|
||||||
|
%let ds=&syslast;
|
||||||
|
proc append base=&outds data=&ds;
|
||||||
|
run;
|
||||||
|
proc sql;
|
||||||
|
drop table &ds;
|
||||||
|
|
||||||
|
%mend;
|
||||||
89
base/mp_assertdsobs.sas
Normal file
89
base/mp_assertdsobs.sas
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Asserts the number of observations in a dataset
|
||||||
|
@details Useful in the context of writing sasjs tests. The results of the
|
||||||
|
test are _appended_ to the &outds. table.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
%mp_assertdsobs(sashelp.class) %* tests if any observations are present;
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_nobs.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
|
||||||
|
@param [in] inds input dataset to test for presence of observations
|
||||||
|
@param [in] desc= (Testing observations) The user provided test description
|
||||||
|
@param [in] test= (HASOBS) The test to apply. Valid values are:
|
||||||
|
@li HASOBS - Test is a PASS if the input dataset has any observations
|
||||||
|
@li EMPTY - Test is a PASS if input dataset is empty
|
||||||
|
@li EQUALS [integer] - Test passes if obs count matches the provided integer
|
||||||
|
@param [out] outds= (work.test_results) The output dataset to contain the
|
||||||
|
results. If it does not exist, it will be created, with the following format:
|
||||||
|
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|
||||||
|
|---|---|---|
|
||||||
|
|User Provided description|PASS|Dataset &inds has XX obs|
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_assertcolvals.sas
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_assertdsobs(inds,
|
||||||
|
test=HASOBS,
|
||||||
|
desc=Testing observations,
|
||||||
|
outds=work.test_results
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%local nobs;
|
||||||
|
%let nobs=%mf_nobs(&inds);
|
||||||
|
%let test=%upcase(&test);
|
||||||
|
|
||||||
|
%if %substr(&test.xxxxx,1,6)=EQUALS %then %do;
|
||||||
|
%let val=%scan(&test,2,%str( ));
|
||||||
|
%mp_abort(iftrue= (%DATATYP(&val)=CHAR)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Invalid test - &test, expected EQUALS [integer])
|
||||||
|
)
|
||||||
|
%let test=EQUALS;
|
||||||
|
%end;
|
||||||
|
%else %if &test ne HASOBS and &test ne EMPTY %then %do;
|
||||||
|
%mp_abort(
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(Invalid test - &test)
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
|
||||||
|
data;
|
||||||
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
|
test_description=symget('desc');
|
||||||
|
test_result='FAIL';
|
||||||
|
test_comments="&sysmacroname: Dataset &inds has &nobs observations";
|
||||||
|
%if &test=HASOBS %then %do;
|
||||||
|
if &nobs>0 then test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %if &test=EMPTY %then %do;
|
||||||
|
if &nobs=0 then test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %if &test=EQUALS %then %do;
|
||||||
|
if &nobs=&val then test_result='PASS';
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
test_comments="&sysmacroname: Unsatisfied test condition - &test";
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%local ds;
|
||||||
|
%let ds=&syslast;
|
||||||
|
|
||||||
|
proc append base=&outds data=&ds;
|
||||||
|
run;
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
drop table &ds;
|
||||||
|
|
||||||
|
%mend;
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
%local i setds nvars;
|
%local i setds nvars;
|
||||||
|
|
||||||
%if not %sysfunc(exist(&base_ds)) %then %do;
|
%if not %sysfunc(exist(&base_ds)) %then %do;
|
||||||
%put WARNING: &base_ds does not exist;
|
%put %str(WARN)ING: &base_ds does not exist;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ select count(*) into: nvars from dictionary.columns
|
|||||||
where libname="%scan(%upcase(&base_ds),1)"
|
where libname="%scan(%upcase(&base_ds),1)"
|
||||||
and memname="%scan(%upcase(&base_ds),2)";
|
and memname="%scan(%upcase(&base_ds),2)";
|
||||||
%if &nvars=0 %then %do;
|
%if &nvars=0 %then %do;
|
||||||
%put WARNING: Dataset &base_ds has no variables! It will not be converted.;
|
%put %str(WARN)ING: Dataset &base_ds has no variables, will not be converted.;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
%if not %sysfunc(exist(&ds)) %then %do;
|
%if not %sysfunc(exist(&ds)) %then %do;
|
||||||
%put WARNING: &ds does not exist;
|
%put %str(WARN)ING: &ds does not exist;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
188
base/mp_filtercheck.sas
Normal file
188
base/mp_filtercheck.sas
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Checks an input filter table for validity
|
||||||
|
@details Performs checks on the input table to ensure it arrives in the
|
||||||
|
correct format. This is necessary to prevent code injection. Will update
|
||||||
|
SYSCC to 1008 if bad records are found, and call mp_abort.sas for a
|
||||||
|
graceful service exit (configurable).
|
||||||
|
|
||||||
|
Used for dynamic filtering in [Data Controller for SAS®](https://datacontroller.io).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%mp_filtercheck(work.filter,targetds=sashelp.class,outds=work.badrecords)
|
||||||
|
|
||||||
|
The input table should have the following format:
|
||||||
|
|
||||||
|
|GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$4000|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
|AND|AND|1|AGE|=|12|
|
||||||
|
|AND|AND|1|SEX|<=|'M'|
|
||||||
|
|AND|OR|2|Name|NOT IN|('Jane','Alfred')|
|
||||||
|
|AND|OR|2|Weight|>=|7|
|
||||||
|
|
||||||
|
Rules applied:
|
||||||
|
|
||||||
|
@li GROUP_LOGIC - only AND/OR
|
||||||
|
@li SUBGROUP_LOGIC - only AND/OR
|
||||||
|
@li SUBGROUP_ID - only integers
|
||||||
|
@li VARIABLE_NM - must be in the target table
|
||||||
|
@li OPERATOR_NM - only =/>/</<=/>=/BETWEEN/IN/NOT IN/NE/CONTAINS
|
||||||
|
@li RAW_VALUE - no unquoted values except integers, commas and spaces.
|
||||||
|
|
||||||
|
@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] targetds= The target dataset against which to verify VARIABLE_NM
|
||||||
|
@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
|
||||||
|
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
|
||||||
|
processes should check this table (and return code) before continuing.
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
@li mf_getvartype.sas
|
||||||
|
@li mf_nobs.sas
|
||||||
|
@li mp_filtergenerate.sas
|
||||||
|
@li mp_filtervalidate.sas
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_filtergenerate.sas
|
||||||
|
@li mp_filtervalidate.sas
|
||||||
|
|
||||||
|
@version 9.3
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
@todo Support date / hex / name literals and exponents in RAW_VALUE field
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_filtercheck(inds,targetds=,outds=work.badrecords,abort=YES);
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc - on macro entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Validate input column */
|
||||||
|
%local vtype;
|
||||||
|
%let vtype=%mf_getvartype(&inds,RAW_VALUE);
|
||||||
|
%mp_abort(iftrue=(&abort=YES and &vtype ne C),
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(%str(ERR)OR: RAW_VALUE must be character)
|
||||||
|
)
|
||||||
|
%if &vtype ne C %then %do;
|
||||||
|
%put &sysmacroname: RAW_VALUE must be character;
|
||||||
|
%let syscc=42;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitise the values based on valid value lists, then strip out
|
||||||
|
* quotes, commas, periods and spaces.
|
||||||
|
* Only numeric values should remain
|
||||||
|
*/
|
||||||
|
%local reason_cd;
|
||||||
|
data &outds;
|
||||||
|
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
|
||||||
|
OPERATOR_NM $10 RAW_VALUE $4000;*/
|
||||||
|
set &inds;
|
||||||
|
length reason_cd $32;
|
||||||
|
|
||||||
|
/* closed list checks */
|
||||||
|
if GROUP_LOGIC not in ('AND','OR') then do;
|
||||||
|
REASON_CD='GROUP_LOGIC should be either AND or OR';
|
||||||
|
putlog REASON_CD= GROUP_LOGIC=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
if SUBGROUP_LOGIC not in ('AND','OR') then do;
|
||||||
|
REASON_CD='SUBGROUP_LOGIC should be either AND or OR';
|
||||||
|
putlog REASON_CD= SUBGROUP_LOGIC=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
if mod(SUBGROUP_ID,1) ne 0 then do;
|
||||||
|
REASON_CD='SUBGROUP_ID should be integer';
|
||||||
|
putlog REASON_CD= SUBGROUP_ID=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
if upcase(VARIABLE_NM) not in
|
||||||
|
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
|
||||||
|
then do;
|
||||||
|
REASON_CD="VARIABLE_NM not in &targetds";
|
||||||
|
putlog REASON_CD= VARIABLE_NM=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
if OPERATOR_NM not in
|
||||||
|
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
||||||
|
then do;
|
||||||
|
REASON_CD='Invalid OPERATOR_NM';
|
||||||
|
putlog REASON_CD= OPERATOR_NM=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* special logic */
|
||||||
|
if OPERATOR_NM='BETWEEN' then raw_value1=tranwrd(raw_value,' AND ','');
|
||||||
|
else if OPERATOR_NM in ('IN','NOT IN') then do;
|
||||||
|
if substr(raw_value,1,1) ne '('
|
||||||
|
or substr(cats(reverse(raw_value)),1,1) ne ')'
|
||||||
|
then do;
|
||||||
|
REASON_CD='Missing brackets in RAW_VALUE';
|
||||||
|
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
|
||||||
|
end;
|
||||||
|
else raw_value1=raw_value;
|
||||||
|
|
||||||
|
/* remove nested literals eg '' */
|
||||||
|
raw_value1=tranwrd(raw_value1,"''",'');
|
||||||
|
|
||||||
|
/* now match string literals (always single quotes) */
|
||||||
|
raw_value2=raw_value1;
|
||||||
|
regex = prxparse("s/(\').*?(\')//");
|
||||||
|
call prxchange(regex,-1,raw_value2);
|
||||||
|
|
||||||
|
/* remove commas and periods*/
|
||||||
|
raw_value3=compress(raw_value2,',.');
|
||||||
|
|
||||||
|
/* output records that contain values other than digits and spaces */
|
||||||
|
if notdigit(compress(raw_value3,' '))>0 then do;
|
||||||
|
putlog raw_value3= $hex32.;
|
||||||
|
REASON_CD='Invalid RAW_VALUE';
|
||||||
|
putlog REASON_CD= raw_value= raw_value1= raw_value2= raw_value3=;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
|
||||||
|
run;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
set &outds;
|
||||||
|
call symputx('REASON_CD',reason_cd,'l');
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_abort(iftrue=(&abort=YES and %mf_nobs(&outds)>0),
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(Filter issues in &inds, reason: &reason_cd, details in &outds)
|
||||||
|
)
|
||||||
|
|
||||||
|
%if %mf_nobs(&outds)>0 %then %do;
|
||||||
|
%let syscc=1008;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syntax checking passed but it does not mean the filter is valid
|
||||||
|
* for that we can run a proc sql validate query
|
||||||
|
*/
|
||||||
|
%local fref1;
|
||||||
|
%let fref1=%mf_getuniquefileref();
|
||||||
|
%mp_filtergenerate(&inds,outref=&fref1)
|
||||||
|
|
||||||
|
/* this macro will also set syscc to 1008 if any issues found */
|
||||||
|
%mp_filtervalidate(&fref1,&targetds,outds=&outds,abort=&abort)
|
||||||
|
|
||||||
|
%mend mp_filtercheck;
|
||||||
102
base/mp_filtergenerate.sas
Normal file
102
base/mp_filtergenerate.sas
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Generates a filter clause from an input table, to a fileref
|
||||||
|
@details Uses the input table to generate an output filter clause.
|
||||||
|
This feature is used to create dynamic dropdowns in [Data Controller for SAS®](
|
||||||
|
https://datacontroller.io). The input table should be in the format below:
|
||||||
|
|
||||||
|
|GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$4000|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
|AND|AND|1|AGE|=|12|
|
||||||
|
|AND|AND|1|SEX|<=|'M'|
|
||||||
|
|AND|OR|2|Name|NOT IN|('Jane','Alfred')|
|
||||||
|
|AND|OR|2|Weight|>=|7|
|
||||||
|
|
||||||
|
Note - if the above table is received from an external client, the values
|
||||||
|
should first be validated using the mp_filtercheck.sas macro to avoid risk
|
||||||
|
of SQL injection.
|
||||||
|
|
||||||
|
To generate the filter, run the following code:
|
||||||
|
|
||||||
|
data work.filtertable;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,AGE,=,12
|
||||||
|
AND,AND,1,SEX,<=,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
|
||||||
|
AND,OR,2,Weight,>=,7
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_filtergenerate(work.filtertable,outref=myfilter)
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile myfilter;
|
||||||
|
input;
|
||||||
|
put _infile_;
|
||||||
|
run;
|
||||||
|
|
||||||
|
Will write the following query to the log:
|
||||||
|
|
||||||
|
> (
|
||||||
|
> AGE = 12
|
||||||
|
> AND
|
||||||
|
> SEX <= 'M'
|
||||||
|
> ) AND (
|
||||||
|
> Name NOT IN ('Jane','Alfred')
|
||||||
|
> OR
|
||||||
|
> Weight >= 7
|
||||||
|
> )
|
||||||
|
|
||||||
|
@param [in] inds The input table with query values
|
||||||
|
@param [out] outref= The output fileref to contain the filter clause. Will
|
||||||
|
be created (or replaced).
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_filtercheck.sas
|
||||||
|
@li mp_filtervalidate.sas
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mf_nobs.sas
|
||||||
|
|
||||||
|
@version 9.3
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_filtergenerate(inds,outref=filter);
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc - on macro entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
filename &outref temp;
|
||||||
|
|
||||||
|
%if %mf_nobs(&inds)=0 %then %do;
|
||||||
|
/* ensure we have a default filter */
|
||||||
|
data _null_;
|
||||||
|
file &outref;
|
||||||
|
put '1=1';
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
data _null_;
|
||||||
|
file &outref lrecl=32800;
|
||||||
|
set &inds end=last;
|
||||||
|
by SUBGROUP_ID;
|
||||||
|
if _n_=1 then put '((';
|
||||||
|
else if first.SUBGROUP_ID then put +1 GROUP_LOGIC '(';
|
||||||
|
else put +2 SUBGROUP_LOGIC;
|
||||||
|
|
||||||
|
put +4 VARIABLE_NM OPERATOR_NM RAW_VALUE;
|
||||||
|
|
||||||
|
if last.SUBGROUP_ID then put ')'@;
|
||||||
|
if last then put ')';
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend;
|
||||||
104
base/mp_filtervalidate.sas
Normal file
104
base/mp_filtervalidate.sas
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Checks a generated filter query for validity
|
||||||
|
@details Runs a generated filter in proc sql with the validate option.
|
||||||
|
Used in mp_filtercheck.sas in an fcmp container.
|
||||||
|
|
||||||
|
Built to support dynamic filtering in
|
||||||
|
[Data Controller for SAS®](https://datacontroller.io).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
data work.filtertable;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,AGE,=,12
|
||||||
|
AND,AND,1,SEX,<=,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
|
||||||
|
AND,OR,2,Weight,>=,7
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_filtergenerate(work.filtertable,outref=myfilter)
|
||||||
|
|
||||||
|
%mp_filtervalidate(myfilter,sashelp.class)
|
||||||
|
|
||||||
|
|
||||||
|
@returns The SYSCC value will be 1008 if there are validation issues.
|
||||||
|
|
||||||
|
@param [in] inref The input fileref to validate (generated by
|
||||||
|
mp_filtergenerate.sas)
|
||||||
|
@param [in] targetds The target dataset against which to verify the query
|
||||||
|
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
||||||
|
@param [out] outds= (work.mp_filtervalidate) Output dataset containing the
|
||||||
|
error / warning message, if one exists. If this table contains any rows,
|
||||||
|
there are problems!
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_nobs.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li mp_filtercheck.sas
|
||||||
|
@li mp_filtergenerate.sas
|
||||||
|
|
||||||
|
@version 9.3
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_filtervalidate(inref,targetds,abort=YES,outds=work.mp_filtervalidate);
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (&syscc ne 0 or &syserr ne 0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(syscc=&syscc / syserr=&syserr - on macro entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
%local fref1;
|
||||||
|
%let fref1=%mf_getuniquefileref();
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
file &fref1;
|
||||||
|
infile &inref end=eof;
|
||||||
|
if _n_=1 then do;
|
||||||
|
put "proc sql;";
|
||||||
|
put "validate select * from &targetds";
|
||||||
|
put "where " ;
|
||||||
|
end;
|
||||||
|
input;
|
||||||
|
put _infile_;
|
||||||
|
putlog _infile_;
|
||||||
|
if eof then put ";quit;";
|
||||||
|
run;
|
||||||
|
|
||||||
|
%inc &fref1;
|
||||||
|
|
||||||
|
data &outds;
|
||||||
|
if &sqlrc or &syscc or &syserr then do;
|
||||||
|
REASON_CD=coalescec(symget('SYSERRORTEXT'),symget('SYSWARNINGTEXT'));
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
else stop;
|
||||||
|
run;
|
||||||
|
|
||||||
|
filename &fref1 clear;
|
||||||
|
|
||||||
|
%if %mf_nobs(&outds)>0 %then %do;
|
||||||
|
%if &abort=YES %then %do;
|
||||||
|
data _null_;
|
||||||
|
set &outds;
|
||||||
|
call symputx('REASON_CD',reason_cd,'l');
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
%mp_abort(
|
||||||
|
mac=&sysmacroname,
|
||||||
|
msg=%str(Filter issues in &inref: %quote(&reason_cd))
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
%let syscc=1008;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend;
|
||||||
75
base/mp_hashdataset.sas
Normal file
75
base/mp_hashdataset.sas
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Returns a unique hash for a dataset
|
||||||
|
@details Ignores metadata attributes, used only to hash values. Compared
|
||||||
|
datasets must be in the same order.
|
||||||
|
|
||||||
|
%mp_hashdataset(sashelp.class,outds=myhash)
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
set work.myhash;
|
||||||
|
put hashkey=;
|
||||||
|
run;
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getattrn.sas
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
@li mf_getvartype.sas
|
||||||
|
|
||||||
|
@param [in] libds dataset to hash
|
||||||
|
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This
|
||||||
|
will contain one column (hashkey) with one observation (a hex32.
|
||||||
|
representation of the input hash)
|
||||||
|
|hashkey:$32.|
|
||||||
|
|---|
|
||||||
|
|28ABC74ABFC45F50794237BA5566E6CA|
|
||||||
|
|
||||||
|
@version 9.2
|
||||||
|
@author Allan Bowe
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_hashdataset(
|
||||||
|
libds,
|
||||||
|
outds=
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
%if %mf_getattrn(&libds,NLOBS)=0 %then %do;
|
||||||
|
%put %str(WARN)ING: Dataset &libds is empty;, or is not a dataset;
|
||||||
|
%end;
|
||||||
|
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
|
||||||
|
%put %str(ERR)OR: Dataset &libds is not a dataset;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%local keyvar /* roll up the md5 */
|
||||||
|
prevkeyvar /* retain prev record md5 */
|
||||||
|
lastvar /* last var in input ds */
|
||||||
|
varlist var i;
|
||||||
|
/* avoid naming conflict for hash key vars */
|
||||||
|
%let keyvar=%mf_getuniquename();
|
||||||
|
%let prevkeyvar=%mf_getuniquename();
|
||||||
|
%let lastvar=%mf_getuniquename();
|
||||||
|
%let varlist=%mf_getvarlist(&libds);
|
||||||
|
data &outds(rename=(&keyvar=hashkey) keep=&keyvar);
|
||||||
|
length &prevkeyvar &keyvar $32;
|
||||||
|
retain &prevkeyvar;
|
||||||
|
set &libds end=&lastvar;
|
||||||
|
/* hash should include previous row */
|
||||||
|
&keyvar=put(md5(&prevkeyvar
|
||||||
|
/* loop every column, hashing every individual value */
|
||||||
|
%do i=1 %to %sysfunc(countw(&varlist));
|
||||||
|
%let var=%scan(&varlist,&i,%str( ));
|
||||||
|
%if %mf_getvartype(&libds,&var)=C %then %do;
|
||||||
|
!!put(md5(trim(&var)),$hex32.)
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
!!put(md5(trim(put(&var*1,binary64.))),$hex32.)
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
),$hex32.);
|
||||||
|
&prevkeyvar=&keyvar;
|
||||||
|
if &lastvar then output;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%mend;
|
||||||
@@ -36,8 +36,20 @@
|
|||||||
%let contentype=%upcase(&contenttype);
|
%let contentype=%upcase(&contenttype);
|
||||||
%local platform; %let platform=%mf_getplatform();
|
%local platform; %let platform=%mf_getplatform();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check engine type to avoid the below err message:
|
||||||
|
* > Function is only valid for filerefs using the CACHE access method.
|
||||||
|
*/
|
||||||
|
%local streamweb;
|
||||||
|
%let streamweb=0;
|
||||||
|
data _null_;
|
||||||
|
set sashelp.vextfl(where=(upcase(fileref)="_WEBOUT"));
|
||||||
|
if xengine='STREAM' then call symputx('streamweb',1,'l');
|
||||||
|
run;
|
||||||
|
|
||||||
%if &contentype=ZIP %then %do;
|
%if &contentype=ZIP %then %do;
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/zip');
|
rc=stpsrv_header('Content-type','application/zip');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
@@ -51,7 +63,7 @@
|
|||||||
%end;
|
%end;
|
||||||
%else %if &contentype=EXCEL %then %do;
|
%else %if &contentype=EXCEL %then %do;
|
||||||
/* suitable for XLS format */
|
/* suitable for XLS format */
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/vnd.ms-excel');
|
rc=stpsrv_header('Content-type','application/vnd.ms-excel');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
@@ -64,7 +76,7 @@
|
|||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &contentype=XLSX %then %do;
|
%else %if &contentype=XLSX %then %do;
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type',
|
rc=stpsrv_header('Content-type',
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
@@ -79,7 +91,7 @@
|
|||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &contentype=TEXT %then %do;
|
%else %if &contentype=TEXT %then %do;
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/text');
|
rc=stpsrv_header('Content-type','application/text');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
@@ -92,7 +104,7 @@
|
|||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &contentype=CSV %then %do;
|
%else %if &contentype=CSV %then %do;
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/csv');
|
rc=stpsrv_header('Content-type','application/csv');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
|
|||||||
259
base/mp_testservice.sas
Normal file
259
base/mp_testservice.sas
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
/**
|
||||||
|
@file mp_testservice.sas
|
||||||
|
@brief Will execute a test against a SASjs web service on SAS 9 or Viya
|
||||||
|
@details Prepares the input files and retrieves the resulting datasets from
|
||||||
|
the response JSON.
|
||||||
|
|
||||||
|
%mp_testjob(
|
||||||
|
duration=60*5
|
||||||
|
)
|
||||||
|
|
||||||
|
Note - the _webout fileref should NOT be assigned prior to running this macro.
|
||||||
|
|
||||||
|
@param [in] program The _PROGRAM endpoint to test
|
||||||
|
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
|
||||||
|
follows:
|
||||||
|
inputfiles=inref:filename inref2:filename2
|
||||||
|
@param [in] inputparams=(0) A dataset containing name/value pairs in the
|
||||||
|
following format:
|
||||||
|
|name:$32|value:$1000|
|
||||||
|
|---|---|
|
||||||
|
|stpmacname|some value|
|
||||||
|
|mustbevalidname|can be anything, oops, %abort!!|
|
||||||
|
|
||||||
|
@param [in] debug= (log) Provide the _debug value
|
||||||
|
@param [in] viyaresult=(WEBOUT_JSON) The Viya result type to return. For
|
||||||
|
more info, see mv_getjobresult.sas
|
||||||
|
@param [out] outlib= (0) Output libref to contain the final tables. Set to
|
||||||
|
0 if the service output is not in JSON format.
|
||||||
|
@param [out] outref= (0) Output fileref to create, to contain the full _webout
|
||||||
|
response.
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getplatform.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mp_binarycopy.sas
|
||||||
|
@li mv_getjobresult.sas
|
||||||
|
@li mv_jobflow.sas
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_testservice(program,
|
||||||
|
inputfiles=0,
|
||||||
|
inputparams=0,
|
||||||
|
debug=log,
|
||||||
|
outlib=0,
|
||||||
|
outref=0,
|
||||||
|
viyaresult=WEBOUT_JSON
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
%local mdebug;
|
||||||
|
%if &debug ne 0 %then %do;
|
||||||
|
%let mdebug=1;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let mdebug=0;
|
||||||
|
|
||||||
|
/* sanitise inputparams */
|
||||||
|
%local pcnt;
|
||||||
|
%let pcnt=0;
|
||||||
|
%if &inputparams ne 0 %then %do;
|
||||||
|
data _null_;
|
||||||
|
set &inputparams;
|
||||||
|
if not nvalid(name,'v7') then putlog (_all_)(=);
|
||||||
|
else if name in (
|
||||||
|
'program','inputfiles','inputparams','debug','outlib','outref'
|
||||||
|
) then putlog (_all_)(=);
|
||||||
|
else do;
|
||||||
|
x+1;
|
||||||
|
call symputx(name,quote(cats(value)),'l');
|
||||||
|
call symputx('pval'!!left(x),name,'l');
|
||||||
|
call symputx('pcnt',x,'l');
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
%mp_abort(iftrue= (%mf_nobs(&inputparams) ne &pcnt)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Invalid values in &inputparams)
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
|
||||||
|
|
||||||
|
%local fref1 webref;
|
||||||
|
%let fref1=%mf_getuniquefileref();
|
||||||
|
%let webref=%mf_getuniquefileref();
|
||||||
|
|
||||||
|
%local platform;
|
||||||
|
%let platform=%mf_getplatform();
|
||||||
|
%if &platform=SASMETA %then %do;
|
||||||
|
|
||||||
|
/* parse the input files */
|
||||||
|
%local webcount i var;
|
||||||
|
%if %quote(&inputfiles) ne 0 %then %do;
|
||||||
|
%let webcount=%sysfunc(countw(&inputfiles));
|
||||||
|
%put &=webcount;
|
||||||
|
%do i=1 %to &webcount;
|
||||||
|
%let var=%scan(&inputfiles,&i,%str( ));
|
||||||
|
%local webfref&i webname&i;
|
||||||
|
%let webref&i=%scan(&var,1,%str(:));
|
||||||
|
%let webname&i=%scan(&var,2,%str(:));
|
||||||
|
%put webref&i=&&webref&i;
|
||||||
|
%put webname&i=&&webname&i;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %let webcount=0;
|
||||||
|
|
||||||
|
proc stp program="&program";
|
||||||
|
inputparam _program="&program"
|
||||||
|
%do i=1 %to &webcount;
|
||||||
|
%if &webcount=1 %then %do;
|
||||||
|
_webin_fileref="&&webref&i"
|
||||||
|
_webin_name="&&webname&i"
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
_webin_fileref&i="&&webref&i"
|
||||||
|
_webin_name&i="&&webname&i"
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
_webin_file_count="&webcount"
|
||||||
|
_debug="&debug"
|
||||||
|
%do i=1 %to &pcnt;
|
||||||
|
/* resolve name only, proc stp fetches value */
|
||||||
|
&&pval&i=&&&&&&pval&i
|
||||||
|
%end;
|
||||||
|
;
|
||||||
|
%do i=1 %to &webcount;
|
||||||
|
inputfile &&webref&i;
|
||||||
|
%end;
|
||||||
|
outputfile _webout=&webref;
|
||||||
|
run;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile &webref;
|
||||||
|
file &fref1;
|
||||||
|
input;
|
||||||
|
length line $10000;
|
||||||
|
if index(_infile_,'>>weboutBEGIN<<') then do;
|
||||||
|
line=tranwrd(_infile_,'>>weboutBEGIN<<','');
|
||||||
|
put line;
|
||||||
|
end;
|
||||||
|
else if index(_infile_,'>>weboutEND<<') then do;
|
||||||
|
line=tranwrd(_infile_,'>>weboutEND<<','');
|
||||||
|
put line;
|
||||||
|
stop;
|
||||||
|
end;
|
||||||
|
else put _infile_;
|
||||||
|
run;
|
||||||
|
data _null_;
|
||||||
|
infile &fref1;
|
||||||
|
input;
|
||||||
|
put _infile_;
|
||||||
|
run;
|
||||||
|
%if &outlib ne 0 %then %do;
|
||||||
|
libname &outlib json (&fref1);
|
||||||
|
%end;
|
||||||
|
%if &outref ne 0 %then %do;
|
||||||
|
filename &outref temp;
|
||||||
|
%mp_binarycopy(inref=&webref,outref=&outref)
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %if &platform=SASVIYA %then %do;
|
||||||
|
|
||||||
|
/* prepare inputparams */
|
||||||
|
%local ds1;
|
||||||
|
%let ds1=%mf_getuniquename();
|
||||||
|
%if "&inputparams" ne "0" %then %do;
|
||||||
|
proc transpose data=&inputparams out=&ds1;
|
||||||
|
id name;
|
||||||
|
var value;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
data &ds1;run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* parse the input files - convert to sasjs params */
|
||||||
|
%local webcount i var sasjs_tables;
|
||||||
|
%if %quote(&inputfiles) ne 0 %then %do;
|
||||||
|
%let webcount=%sysfunc(countw(&inputfiles));
|
||||||
|
%put &=webcount;
|
||||||
|
%do i=1 %to &webcount;
|
||||||
|
%let var=%scan(&inputfiles,&i,%str( ));
|
||||||
|
%local webfref&i webname&i sasjs&i.data;
|
||||||
|
%let webref&i=%scan(&var,1,%str(:));
|
||||||
|
%let webname&i=%scan(&var,2,%str(:));
|
||||||
|
%put webref&i=&&webref&i;
|
||||||
|
%put webname&i=&&webname&i;
|
||||||
|
|
||||||
|
%let sasjs_tables=&sasjs_tables &&webname&i;
|
||||||
|
data _null_;
|
||||||
|
infile &&webref&i lrecl=32767;
|
||||||
|
input;
|
||||||
|
if _n_=1 then call symputx("sasjs&i.data",_infile_);
|
||||||
|
else call symputx(
|
||||||
|
"sasjs&i.data",cats(symget("sasjs&i.data"),'0D0A'x,_infile_)
|
||||||
|
);
|
||||||
|
putlog "&sysmacroname infile: " _infile_;
|
||||||
|
run;
|
||||||
|
data &ds1;
|
||||||
|
set &ds1;
|
||||||
|
length sasjs&i.data $32767 sasjs_tables $1000;
|
||||||
|
sasjs&i.data=symget("sasjs&i.data");
|
||||||
|
sasjs_tables=symget("sasjs_tables");
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %let webcount=0;
|
||||||
|
|
||||||
|
data &ds1;
|
||||||
|
retain _program "&program";
|
||||||
|
set &ds1;
|
||||||
|
putlog "&sysmacroname inputparams:";
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mv_jobflow(inds=&ds1
|
||||||
|
,maxconcurrency=1
|
||||||
|
,outds=work.results
|
||||||
|
,outref=&fref1
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
|
/* show the log */
|
||||||
|
data _null_;
|
||||||
|
infile &fref1;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
/* get the uri to fetch results */
|
||||||
|
data _null_;
|
||||||
|
set work.results;
|
||||||
|
call symputx('uri',uri);
|
||||||
|
putlog "&sysmacroname: fetching results for " uri;
|
||||||
|
run;
|
||||||
|
/* fetch results from webout.json */
|
||||||
|
%mv_getjobresult(uri=&uri,
|
||||||
|
result=&viyaresult,
|
||||||
|
outref=&outref,
|
||||||
|
outlib=&outlib,
|
||||||
|
mdebug=&mdebug
|
||||||
|
)
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%put %str(ERR)OR: Unrecognised platform: &platform;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%if &mdebug=0 %then %do;
|
||||||
|
filename &webref clear;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend mp_testservice;
|
||||||
66
base/mp_validatecol.sas
Normal file
66
base/mp_validatecol.sas
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Used to validate variables in a dataset
|
||||||
|
@details Useful when sanitising inputs, to ensure that they arrive with a
|
||||||
|
certain pattern.
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
data test;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input;
|
||||||
|
libds=_infile_;
|
||||||
|
%mp_validatecol(libds,LIBDS,is_libds)
|
||||||
|
datalines4;
|
||||||
|
some.libname
|
||||||
|
!lib.blah
|
||||||
|
%abort
|
||||||
|
definite.ok
|
||||||
|
not.ok!
|
||||||
|
nineletrs._
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
@param [in] incol The column to be validated
|
||||||
|
@param [in] rule The rule to apply. Current rules:
|
||||||
|
@li ISNUM - checks if the variable is numeric
|
||||||
|
@li LIBDS - matches LIBREF.DATASET format
|
||||||
|
@param [out] outcol The variable to create, with the results of the match
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
|
||||||
|
@version 9.3
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_validatecol(incol,rule,outcol);
|
||||||
|
|
||||||
|
/* tempcol is given a unique name with every invocation */
|
||||||
|
%local tempcol;
|
||||||
|
%let tempcol=%mf_getuniquename();
|
||||||
|
|
||||||
|
%if &rule=ISNUM %then %do;
|
||||||
|
/*
|
||||||
|
credit SØREN LASSEN
|
||||||
|
https://sasmacro.blogspot.com/2009/06/welcome-isnum-macro.html
|
||||||
|
*/
|
||||||
|
&tempcol=input(&incol,?? best32.);
|
||||||
|
if missing(&tempcol) then &outcol=0;
|
||||||
|
else &outcol=1;
|
||||||
|
drop &tempcol;
|
||||||
|
%end;
|
||||||
|
%else %if &rule=LIBDS %then %do;
|
||||||
|
/* match libref.dataset */
|
||||||
|
if _n_=1 then do;
|
||||||
|
retain &tempcol;
|
||||||
|
&tempcol=prxparse('/^[_a-z]\w{0,7}\.[_a-z]\w{0,31}$/i');
|
||||||
|
if missing(&tempcol) then do;
|
||||||
|
putlog "%str(ERR)OR: Invalid expression for LIBDS";
|
||||||
|
stop;
|
||||||
|
end;
|
||||||
|
drop &tempcol;
|
||||||
|
end;
|
||||||
|
if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
|
||||||
|
else &outcol=0;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend mp_validatecol;
|
||||||
@@ -70,7 +70,7 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &syscc ge 4 %then %do;
|
%if &syscc ge 4 %then %do;
|
||||||
%put WARNING: SYSCC=&syscc, exiting &sysmacroname;
|
%put %str(WARN)ING: SYSCC=&syscc, exiting &sysmacroname;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ run;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
%if %length(&open_passthrough)>0 %then %do;
|
%if %length(&open_passthrough)>0 %then %do;
|
||||||
%put WARNING: Passthrough option for postgres not yet supported;
|
%put %str(WARN)ING: Passthrough option for postgres not yet supported;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
@@ -455,8 +455,8 @@ run;
|
|||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%put WARNING: Engine &engine is currently unsupported;
|
%put %str(WARN)ING: Engine &engine is currently unsupported;
|
||||||
%put WARNING- Please contact your support team.;
|
%put %str(WARN)ING- Please contact your support team.;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ data _null_;
|
|||||||
putlog (_all_)(=);
|
putlog (_all_)(=);
|
||||||
run;
|
run;
|
||||||
%if &checktype = SASLibrary %then %do;
|
%if &checktype = SASLibrary %then %do;
|
||||||
%put WARNING: Library (&liburi) already exists with libname (&libname) ;
|
%put %str(WARN)ING: Library (&liburi) already exists with libname (&libname);
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ data _null_;
|
|||||||
putlog (_all_)(=);
|
putlog (_all_)(=);
|
||||||
run;
|
run;
|
||||||
%if &checktype = SASLibrary %then %do;
|
%if &checktype = SASLibrary %then %do;
|
||||||
%put WARNING: Library (&liburi) already exists with libref (&libref) ;
|
%put %str(WARN)ING: Library (&liburi) already exists with libref (&libref) ;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ data _null_;
|
|||||||
call symputx('treeuri',uri,'l');
|
call symputx('treeuri',uri,'l');
|
||||||
run;
|
run;
|
||||||
%if &foldertype ne Tree %then %do;
|
%if &foldertype ne Tree %then %do;
|
||||||
%put WARNING: Tree &tree does not exist!;
|
%put %str(WARN)ING: Tree &tree does not exist!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ filename &frefout temp;
|
|||||||
* check SAS version
|
* check SAS version
|
||||||
*/
|
*/
|
||||||
%if %sysevalf(&sysver lt 9.3) %then %do;
|
%if %sysevalf(&sysver lt 9.3) %then %do;
|
||||||
%put WARNING: Version 9.3 or later required;
|
%put %str(WARN)ING: Version 9.3 or later required;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ data _null_;
|
|||||||
call symputx('treeuri',uri,'l');
|
call symputx('treeuri',uri,'l');
|
||||||
run;
|
run;
|
||||||
%if &foldertype ne Tree %then %do;
|
%if &foldertype ne Tree %then %do;
|
||||||
%put WARNING: Tree &tree does not exist!;
|
%put %str(WARN)ING: Tree &tree does not exist!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ data _null_;
|
|||||||
call symputx('stpuri',uri,'l');
|
call symputx('stpuri',uri,'l');
|
||||||
run;
|
run;
|
||||||
%if &cmtype = ClassifierMap %then %do;
|
%if &cmtype = ClassifierMap %then %do;
|
||||||
%put WARNING: Stored Process &stpname already exists in &tree!;
|
%put %str(WARN)ING: Stored Process &stpname already exists in &tree!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -141,14 +141,14 @@ run;
|
|||||||
* Check that the physical file exists
|
* Check that the physical file exists
|
||||||
*/
|
*/
|
||||||
%if %sysfunc(fileexist(&directory/&filename)) ne 1 %then %do;
|
%if %sysfunc(fileexist(&directory/&filename)) ne 1 %then %do;
|
||||||
%put WARNING: FILE *&directory/&filename* NOT FOUND!;
|
%put %str(WARN)ING: FILE *&directory/&filename* NOT FOUND!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &stptype=1 %then %do;
|
%if &stptype=1 %then %do;
|
||||||
/* type 1 STP - where code is stored on filesystem */
|
/* type 1 STP - where code is stored on filesystem */
|
||||||
%if %sysevalf(&sysver lt 9.2) %then %do;
|
%if %sysevalf(&sysver lt 9.2) %then %do;
|
||||||
%put WARNING: Version 9.2 or later required;
|
%put %str(WARN)ING: Version 9.2 or later required;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ run;
|
|||||||
%if &checkdirtype ne Directory %then %do;
|
%if &checkdirtype ne Directory %then %do;
|
||||||
%mm_getdirectories(path=&directory,outds=&outds ,mDebug=&mDebug)
|
%mm_getdirectories(path=&directory,outds=&outds ,mDebug=&mDebug)
|
||||||
%if %mf_nobs(&outds)=0 or %sysfunc(exist(&outds))=0 %then %do;
|
%if %mf_nobs(&outds)=0 or %sysfunc(exist(&outds))=0 %then %do;
|
||||||
%put WARNING: The directory object does not exist for &directory;
|
%put %str(WARN)ING: The directory object does not exist for &directory;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
@@ -180,12 +180,12 @@ run;
|
|||||||
length id $20 type $256;
|
length id $20 type $256;
|
||||||
__rc=metadata_resolve("&treeuri",type,id);
|
__rc=metadata_resolve("&treeuri",type,id);
|
||||||
if type ne 'Tree' then do;
|
if type ne 'Tree' then do;
|
||||||
putlog "WARNING: Invalid tree URI: &treeuri";
|
putlog "%str(WARN)ING: Invalid tree URI: &treeuri";
|
||||||
stopme=1;
|
stopme=1;
|
||||||
end;
|
end;
|
||||||
__rc=metadata_resolve(directoryuri,type,id);
|
__rc=metadata_resolve(directoryuri,type,id);
|
||||||
if type ne 'Directory' then do;
|
if type ne 'Directory' then do;
|
||||||
putlog 'WARNING: Invalid directory URI: ' directoryuri;
|
putlog "%str(WARN)ING: Invalid directory URI: " directoryuri;
|
||||||
stopme=1;
|
stopme=1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ run;
|
|||||||
if type ne 'LogicalServer' then do;
|
if type ne 'LogicalServer' then do;
|
||||||
__rc=metadata_getnobj("omsobj:LogicalServer?@Name='&server'",1,serveruri);
|
__rc=metadata_getnobj("omsobj:LogicalServer?@Name='&server'",1,serveruri);
|
||||||
if serveruri='' then do;
|
if serveruri='' then do;
|
||||||
putlog "WARNING: Invalid server: &server";
|
putlog "%str(WARN)ING: Invalid server: &server";
|
||||||
stopme=1;
|
stopme=1;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -217,7 +217,7 @@ run;
|
|||||||
rc6 = METADATA_SETATTR(prompturi, 'GroupInfo',groupinfo);
|
rc6 = METADATA_SETATTR(prompturi, 'GroupInfo',groupinfo);
|
||||||
|
|
||||||
if sum(of rc1-rc6) ne 0 then do;
|
if sum(of rc1-rc6) ne 0 then do;
|
||||||
putlog 'WARNING: Issue creating prompt.';
|
putlog "%str(WARN)ING: Issue creating prompt.";
|
||||||
if prompturi ne . then do;
|
if prompturi ne . then do;
|
||||||
putlog ' Removing orphan: ' prompturi;
|
putlog ' Removing orphan: ' prompturi;
|
||||||
rc = METADATA_DELOBJ(prompturi);
|
rc = METADATA_DELOBJ(prompturi);
|
||||||
@@ -232,7 +232,7 @@ run;
|
|||||||
rc9=METADATA_SETATTR(fileuri, 'IsARelativeName','1');
|
rc9=METADATA_SETATTR(fileuri, 'IsARelativeName','1');
|
||||||
rc10=METADATA_SETASSN(fileuri, 'Directories','MODIFY',directoryuri);
|
rc10=METADATA_SETASSN(fileuri, 'Directories','MODIFY',directoryuri);
|
||||||
if sum(of rc7-rc10) ne 0 then do;
|
if sum(of rc7-rc10) ne 0 then do;
|
||||||
putlog 'WARNING: Issue creating file.';
|
putlog "%str(WARN)ING: Issue creating file.";
|
||||||
if fileuri ne . then do;
|
if fileuri ne . then do;
|
||||||
putlog ' Removing orphans:' prompturi fileuri;
|
putlog ' Removing orphans:' prompturi fileuri;
|
||||||
rc = METADATA_DELOBJ(prompturi);
|
rc = METADATA_DELOBJ(prompturi);
|
||||||
@@ -251,7 +251,7 @@ run;
|
|||||||
!!"<OutputParameters/></StoredProcess>";
|
!!"<OutputParameters/></StoredProcess>";
|
||||||
rc14= METADATA_SETATTR(texturi, 'StoredText',storedtext);
|
rc14= METADATA_SETATTR(texturi, 'StoredText',storedtext);
|
||||||
if sum(of rc11-rc14) ne 0 then do;
|
if sum(of rc11-rc14) ne 0 then do;
|
||||||
putlog 'WARNING: Issue creating TextStore.';
|
putlog "%str(WARN)ING: Issue creating TextStore.";
|
||||||
if texturi ne . then do;
|
if texturi ne . then do;
|
||||||
putlog ' Removing orphans: ' prompturi fileuri texturi;
|
putlog ' Removing orphans: ' prompturi fileuri texturi;
|
||||||
rc = METADATA_DELOBJ(prompturi);
|
rc = METADATA_DELOBJ(prompturi);
|
||||||
@@ -299,7 +299,7 @@ run;
|
|||||||
%else %if &stptype=2 %then %do;
|
%else %if &stptype=2 %then %do;
|
||||||
/* type 2 stp - code is stored in metadata */
|
/* type 2 stp - code is stored in metadata */
|
||||||
%if %sysevalf(&sysver lt 9.3) %then %do;
|
%if %sysevalf(&sysver lt 9.3) %then %do;
|
||||||
%put WARNING: SAS version 9.3 or later required to create type2 STPs;
|
%put %str(WARN)ING: SAS version 9.3 or later required to create type2 STPs;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
/* check we have the correct ServerContext */
|
/* check we have the correct ServerContext */
|
||||||
@@ -311,7 +311,7 @@ run;
|
|||||||
call symputx('serveruri',serveruri);
|
call symputx('serveruri',serveruri);
|
||||||
run;
|
run;
|
||||||
%if &serveruri=NOTFOUND %then %do;
|
%if &serveruri=NOTFOUND %then %do;
|
||||||
%put WARNING: ServerContext *&server* not found!;
|
%put %str(WARN)ING: ServerContext *&server* not found!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
@@ -382,7 +382,7 @@ run;
|
|||||||
|
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%put WARNING: STPTYPE=*&stptype* not recognised!;
|
%put %str(WARN)ING: STPTYPE=*&stptype* not recognised!;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend;
|
%mend;
|
||||||
@@ -237,8 +237,16 @@ data _null_;
|
|||||||
put '%else %if &action=OPEN %then %do; ';
|
put '%else %if &action=OPEN %then %do; ';
|
||||||
put ' /* fix encoding */ ';
|
put ' /* fix encoding */ ';
|
||||||
put ' OPTIONS NOBOMFILE; ';
|
put ' OPTIONS NOBOMFILE; ';
|
||||||
|
put ' ';
|
||||||
|
put ' /** ';
|
||||||
|
put ' * check engine type to avoid the below err message: ';
|
||||||
|
put ' * > Function is only valid for filerefs using the CACHE access method. ';
|
||||||
|
put ' */ ';
|
||||||
put ' data _null_; ';
|
put ' data _null_; ';
|
||||||
|
put ' set sashelp.vextfl(where=(fileref="_WEBOUT")); ';
|
||||||
|
put ' if xengine=''STREAM'' then do; ';
|
||||||
put ' rc=stpsrv_header(''Content-type'',"text/html; encoding=utf-8"); ';
|
put ' rc=stpsrv_header(''Content-type'',"text/html; encoding=utf-8"); ';
|
||||||
|
put ' end; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' /* setup json */ ';
|
put ' /* setup json */ ';
|
||||||
@@ -252,17 +260,10 @@ data _null_;
|
|||||||
put '%end; ';
|
put '%end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put '%else %if &action=ARR or &action=OBJ %then %do; ';
|
put '%else %if &action=ARR or &action=OBJ %then %do; ';
|
||||||
put ' %if &sysver=9.4 %then %do; ';
|
|
||||||
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
|
|
||||||
put ' ,engine=PROCJSON,dbg=%str(&_debug) ';
|
|
||||||
put ' ) ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' %else %do; ';
|
|
||||||
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
|
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
|
||||||
put ' ,engine=DATASTEP,dbg=%str(&_debug) ';
|
put ' ,engine=DATASTEP,dbg=%str(&_debug) ';
|
||||||
put ' ) ';
|
put ' ) ';
|
||||||
put '%end; ';
|
put '%end; ';
|
||||||
put '%end; ';
|
|
||||||
put '%else %if &action=CLOSE %then %do; ';
|
put '%else %if &action=CLOSE %then %do; ';
|
||||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
put ' %if %str(&_debug) ge 131 %then %do; ';
|
||||||
put ' /* if debug mode, send back first 10 records of each work table also */ ';
|
put ' /* if debug mode, send back first 10 records of each work table also */ ';
|
||||||
@@ -277,14 +278,14 @@ data _null_;
|
|||||||
put ' i+1; ';
|
put ' i+1; ';
|
||||||
put ' call symputx(''wt''!!left(i),name,''l''); ';
|
put ' call symputx(''wt''!!left(i),name,''l''); ';
|
||||||
put ' call symputx(''wtcnt'',i,''l''); ';
|
put ' call symputx(''wtcnt'',i,''l''); ';
|
||||||
put ' data _null_; file &fref encoding=''utf-8''; ';
|
put ' data _null_; file &fref mod encoding=''utf-8''; ';
|
||||||
put ' put ",""WORK"":{"; ';
|
put ' put ",""WORK"":{"; ';
|
||||||
put ' %do i=1 %to &wtcnt; ';
|
put ' %do i=1 %to &wtcnt; ';
|
||||||
put ' %let wt=&&wt&i; ';
|
put ' %let wt=&&wt&i; ';
|
||||||
put ' proc contents noprint data=&wt ';
|
put ' proc contents noprint data=&wt ';
|
||||||
put ' out=_data_ (keep=name type length format:); ';
|
put ' out=_data_ (keep=name type length format:); ';
|
||||||
put ' run;%let tempds=%scan(&syslast,2,.); ';
|
put ' run;%let tempds=%scan(&syslast,2,.); ';
|
||||||
put ' data _null_; file &fref encoding=''utf-8''; ';
|
put ' data _null_; file &fref mod encoding=''utf-8''; ';
|
||||||
put ' dsid=open("WORK.&wt",''is''); ';
|
put ' dsid=open("WORK.&wt",''is''); ';
|
||||||
put ' nlobs=attrn(dsid,''NLOBS''); ';
|
put ' nlobs=attrn(dsid,''NLOBS''); ';
|
||||||
put ' nvars=attrn(dsid,''NVARS''); ';
|
put ' nvars=attrn(dsid,''NVARS''); ';
|
||||||
@@ -295,10 +296,10 @@ data _null_;
|
|||||||
put ' put '',"nvars":'' nvars; ';
|
put ' put '',"nvars":'' nvars; ';
|
||||||
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
|
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
|
||||||
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
|
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
|
||||||
put ' data _null_; file &fref encoding=''utf-8''; ';
|
put ' data _null_; file &fref mod encoding=''utf-8''; ';
|
||||||
put ' put "}"; ';
|
put ' put "}"; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' data _null_; file &fref encoding=''utf-8''; ';
|
put ' data _null_; file &fref mod encoding=''utf-8''; ';
|
||||||
put ' put "}"; ';
|
put ' put "}"; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ data _null_;
|
|||||||
call symputx('stpuri',uri,'l');
|
call symputx('stpuri',uri,'l');
|
||||||
run;
|
run;
|
||||||
%if &type ne Document %then %do;
|
%if &type ne Document %then %do;
|
||||||
%put WARNING: No Document found at ⌖
|
%put %str(WARN)ING: No Document found at ⌖
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ data _null_;
|
|||||||
when ('
') rec='0D'x;
|
when ('
') rec='0D'x;
|
||||||
when ('$' ) rec='$' ;
|
when ('$' ) rec='$' ;
|
||||||
when ('	') rec='09'x;
|
when ('	') rec='09'x;
|
||||||
otherwise putlog "WARNING: missing value for " entity=;
|
otherwise putlog "%str(WARN)ING: missing value for " entity=;
|
||||||
end;
|
end;
|
||||||
rc =fput(fileid, substr(rec,1,1));
|
rc =fput(fileid, substr(rec,1,1));
|
||||||
rc =fwrite(fileid);
|
rc =fwrite(fileid);
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Writes the code of an to an external file, or the log if none provided
|
@brief Writes the code of an STP to an external file
|
||||||
@details Get the
|
@details Fetches the SAS code from a Stored Process where the code is stored
|
||||||
|
in metadata.
|
||||||
|
|
||||||
usage:
|
Usage:
|
||||||
|
|
||||||
%mm_getstpcode(tree=/some/meta/path
|
%mm_getstpcode(tree=/some/meta/path
|
||||||
,name=someSTP
|
,name=someSTP
|
||||||
,outloc=/some/unquoted/filename.ext
|
,outloc=/some/unquoted/filename.ext
|
||||||
)
|
)
|
||||||
|
|
||||||
@param tree= The metadata path of the Stored Process (can also contain name)
|
@param [in] tree= The metadata path of the Stored Process (can also contain
|
||||||
@param name= Stored Process name. Leave blank if included above.
|
name)
|
||||||
@param outloc= full and unquoted path to the desired text file. This will be
|
@param [in] name= Stored Process name. Leave blank if included above.
|
||||||
overwritten if it already exists. If not provided, the code will be written
|
@param [out] outloc= (0) full and unquoted path to the desired text file.
|
||||||
to the log.
|
This will be overwritten if it already exists.
|
||||||
|
@param [out] outref= (0) Fileref to which to write the code.
|
||||||
|
@param [out] showlog=(NO) Set to YES to print log to the window
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
@@ -23,8 +29,10 @@
|
|||||||
%macro mm_getstpcode(
|
%macro mm_getstpcode(
|
||||||
tree=/User Folders/sasdemo/somestp
|
tree=/User Folders/sasdemo/somestp
|
||||||
,name=
|
,name=
|
||||||
,outloc=
|
,outloc=0
|
||||||
|
,outref=0
|
||||||
,mDebug=1
|
,mDebug=1
|
||||||
|
,showlog=NO
|
||||||
);
|
);
|
||||||
|
|
||||||
%local mD;
|
%local mD;
|
||||||
@@ -92,14 +100,18 @@ data _null_;
|
|||||||
stop;
|
stop;
|
||||||
|
|
||||||
%local outeng;
|
%local outeng;
|
||||||
%if %length(&outloc)=0 %then %let outeng=TEMP;
|
%if "&outloc"="0" %then %let outeng=TEMP;
|
||||||
%else %let outeng="&outloc";
|
%else %let outeng="&outloc";
|
||||||
|
%local fref;
|
||||||
|
%if &outref=0 %then %let fref=%mf_getuniquefileref();
|
||||||
|
%else %let fref=&outref;
|
||||||
|
|
||||||
/* read the content, byte by byte, resolving escaped chars */
|
/* read the content, byte by byte, resolving escaped chars */
|
||||||
filename __outdoc &outeng lrecl=100000;
|
filename &fref &outeng lrecl=100000;
|
||||||
data _null_;
|
data _null_;
|
||||||
length filein 8 fileid 8;
|
length filein 8 fileid 8;
|
||||||
filein = fopen("__getdoc","I",1,"B");
|
filein = fopen("__getdoc","I",1,"B");
|
||||||
fileid = fopen("__outdoc","O",1,"B");
|
fileid = fopen("&fref","O",1,"B");
|
||||||
rec = "20"x;
|
rec = "20"x;
|
||||||
length entity $6;
|
length entity $6;
|
||||||
do while(fread(filein)=0);
|
do while(fread(filein)=0);
|
||||||
@@ -140,9 +152,9 @@ data _null_;
|
|||||||
rc=fclose(fileid);
|
rc=fclose(fileid);
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%if &outeng=TEMP %then %do;
|
%if &showlog=YES %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
infile __outdoc lrecl=32767 end=last;
|
infile &fref lrecl=32767 end=last;
|
||||||
input;
|
input;
|
||||||
if _n_=1 then putlog '>>stpcodeBEGIN<<';
|
if _n_=1 then putlog '>>stpcodeBEGIN<<';
|
||||||
putlog _infile_;
|
putlog _infile_;
|
||||||
@@ -151,6 +163,8 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
filename __getdoc clear;
|
filename __getdoc clear;
|
||||||
filename __outdoc clear;
|
%if &outref=0 %then %do;
|
||||||
|
filename &fref clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
%mend;
|
%mend mm_getstpcode;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ run;
|
|||||||
when ('
') rec='0D'x;
|
when ('
') rec='0D'x;
|
||||||
when ('$' ) rec='$' ;
|
when ('$' ) rec='$' ;
|
||||||
when ('	') rec='09'x;
|
when ('	') rec='09'x;
|
||||||
otherwise putlog "WARNING: missing value for " entity=;
|
otherwise putlog "%str(WARN)ING: missing value for " entity=;
|
||||||
end;
|
end;
|
||||||
rc =fput(fileid, substr(rec,1,1));
|
rc =fput(fileid, substr(rec,1,1));
|
||||||
rc =fwrite(fileid);
|
rc =fwrite(fileid);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
%if &appuri=stopifempty %then %do;
|
%if &appuri=stopifempty %then %do;
|
||||||
%put WARNING: &app.(Application) not found!;
|
%put %str(WARN)ING: &app.(Application) not found!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
%if &tsuri=stopifempty %then %do;
|
%if &tsuri=stopifempty %then %do;
|
||||||
%put WARNING: &path/&name.(Document) not found!;
|
%put %str(WARN)ING: &path/&name.(Document) not found!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if %length(&text)<2 %then %do;
|
%if %length(&text)<2 %then %do;
|
||||||
%put WARNING: No text supplied!!;
|
%put %str(WARN)ING: No text supplied!!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ data _null_;
|
|||||||
call symputx('stpuri',uri,'l');
|
call symputx('stpuri',uri,'l');
|
||||||
run;
|
run;
|
||||||
%if &cmtype ne ClassifierMap %then %do;
|
%if &cmtype ne ClassifierMap %then %do;
|
||||||
%put WARNING: No Stored Process found at ⌖
|
%put %str(WARN)ING: No Stored Process found at ⌖
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -68,12 +68,12 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
%if &tsuri=stopifempty %then %do;
|
%if &tsuri=stopifempty %then %do;
|
||||||
%put WARNING: &stp.(StoredProcess) not found!;
|
%put %str(WARN)ING: &stp.(StoredProcess) not found!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if %length(&stpcode)<2 %then %do;
|
%if %length(&stpcode)<2 %then %do;
|
||||||
%put WARNING: No SAS code supplied!!;
|
%put %str(WARN)ING: No SAS code supplied!!;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,16 @@
|
|||||||
%else %if &action=OPEN %then %do;
|
%else %if &action=OPEN %then %do;
|
||||||
/* fix encoding */
|
/* fix encoding */
|
||||||
OPTIONS NOBOMFILE;
|
OPTIONS NOBOMFILE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check engine type to avoid the below err message:
|
||||||
|
* > Function is only valid for filerefs using the CACHE access method.
|
||||||
|
*/
|
||||||
data _null_;
|
data _null_;
|
||||||
|
set sashelp.vextfl(where=(fileref="_WEBOUT"));
|
||||||
|
if xengine='STREAM' then do;
|
||||||
rc=stpsrv_header('Content-type',"text/html; encoding=utf-8");
|
rc=stpsrv_header('Content-type',"text/html; encoding=utf-8");
|
||||||
|
end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
/* setup json */
|
/* setup json */
|
||||||
@@ -83,17 +91,10 @@
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%else %if &action=ARR or &action=OBJ %then %do;
|
%else %if &action=ARR or &action=OBJ %then %do;
|
||||||
%if &sysver=9.4 %then %do;
|
|
||||||
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
|
|
||||||
,engine=PROCJSON,dbg=%str(&_debug)
|
|
||||||
)
|
|
||||||
%end;
|
|
||||||
%else %do;
|
|
||||||
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
|
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
|
||||||
,engine=DATASTEP,dbg=%str(&_debug)
|
,engine=DATASTEP,dbg=%str(&_debug)
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%end;
|
|
||||||
%else %if &action=CLOSE %then %do;
|
%else %if &action=CLOSE %then %do;
|
||||||
%if %str(&_debug) ge 131 %then %do;
|
%if %str(&_debug) ge 131 %then %do;
|
||||||
/* if debug mode, send back first 10 records of each work table also */
|
/* if debug mode, send back first 10 records of each work table also */
|
||||||
@@ -108,14 +109,14 @@
|
|||||||
i+1;
|
i+1;
|
||||||
call symputx('wt'!!left(i),name,'l');
|
call symputx('wt'!!left(i),name,'l');
|
||||||
call symputx('wtcnt',i,'l');
|
call symputx('wtcnt',i,'l');
|
||||||
data _null_; file &fref encoding='utf-8';
|
data _null_; file &fref mod encoding='utf-8';
|
||||||
put ",""WORK"":{";
|
put ",""WORK"":{";
|
||||||
%do i=1 %to &wtcnt;
|
%do i=1 %to &wtcnt;
|
||||||
%let wt=&&wt&i;
|
%let wt=&&wt&i;
|
||||||
proc contents noprint data=&wt
|
proc contents noprint data=&wt
|
||||||
out=_data_ (keep=name type length format:);
|
out=_data_ (keep=name type length format:);
|
||||||
run;%let tempds=%scan(&syslast,2,.);
|
run;%let tempds=%scan(&syslast,2,.);
|
||||||
data _null_; file &fref encoding='utf-8';
|
data _null_; file &fref mod encoding='utf-8';
|
||||||
dsid=open("WORK.&wt",'is');
|
dsid=open("WORK.&wt",'is');
|
||||||
nlobs=attrn(dsid,'NLOBS');
|
nlobs=attrn(dsid,'NLOBS');
|
||||||
nvars=attrn(dsid,'NVARS');
|
nvars=attrn(dsid,'NVARS');
|
||||||
@@ -126,10 +127,10 @@
|
|||||||
put ',"nvars":' nvars;
|
put ',"nvars":' nvars;
|
||||||
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
|
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
|
||||||
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
|
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
|
||||||
data _null_; file &fref encoding='utf-8';
|
data _null_; file &fref mod encoding='utf-8';
|
||||||
put "}";
|
put "}";
|
||||||
%end;
|
%end;
|
||||||
data _null_; file &fref encoding='utf-8';
|
data _null_; file &fref mod encoding='utf-8';
|
||||||
put "}";
|
put "}";
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 146 KiB |
@@ -1,6 +1,12 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
|
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
|
||||||
"macroFolders": ["base", "meta", "metax", "viya", "lua"],
|
"macroFolders": [
|
||||||
|
"base",
|
||||||
|
"meta",
|
||||||
|
"metax",
|
||||||
|
"viya",
|
||||||
|
"lua"
|
||||||
|
],
|
||||||
"docConfig": {
|
"docConfig": {
|
||||||
"displayMacroCore": false,
|
"displayMacroCore": false,
|
||||||
"enableLineage": false,
|
"enableLineage": false,
|
||||||
@@ -9,5 +15,34 @@
|
|||||||
"logo": "Macro_core_website_1.png",
|
"logo": "Macro_core_website_1.png",
|
||||||
"readMe": "../../README.md"
|
"readMe": "../../README.md"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"defaultTarget": "viya",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"name": "viya",
|
||||||
|
"serverUrl": "https://sas.analytium.co.uk",
|
||||||
|
"serverType": "SASVIYA",
|
||||||
|
"appLoc": "/Public/temp/macrocore",
|
||||||
|
"deployConfig": {
|
||||||
|
"deployServicePack": true
|
||||||
|
},
|
||||||
|
"macroFolders": [
|
||||||
|
"base",
|
||||||
|
"meta",
|
||||||
|
"metax",
|
||||||
|
"viya",
|
||||||
|
"lua",
|
||||||
|
"tests/base",
|
||||||
|
"tests/viya"
|
||||||
|
],
|
||||||
|
"contextName": "SAS Job Execution compute context",
|
||||||
|
"testConfig": {
|
||||||
|
"initProgram": "tests/testinit.sas",
|
||||||
|
"termProgram": "tests/testterm.sas",
|
||||||
|
"macroVars": {
|
||||||
|
"mcTestAppLoc": "/Public/temp/macrocore"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
60
tests/base/mf_getvarlist.test.sas
Normal file
60
tests/base/mf_getvarlist.test.sas
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mf_getvarlist macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
%let test1=%mf_getvarlist(sashelp.class);
|
||||||
|
%let test2=%mf_getvarlist(sashelp.class,dlm=X);
|
||||||
|
%let test3=%mf_getvarlist(sashelp.class,dlm=%str(,),quote=double);
|
||||||
|
%let test4=%mf_getvarlist(sashelp.class,typefilter=N);
|
||||||
|
%let test5=%mf_getvarlist(sashelp.class,typefilter=C);
|
||||||
|
|
||||||
|
data work.test_results;
|
||||||
|
length test_description $256 test_result $4 test_comments base result $256;
|
||||||
|
test_description="Basic test";
|
||||||
|
base=symget('test1');
|
||||||
|
result='Name Sex Age Height Weight';
|
||||||
|
if base=result then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_comments="Comparing "!!trim(base)!!' vs '!!trim(result);
|
||||||
|
output;
|
||||||
|
|
||||||
|
test_description="DLM test";
|
||||||
|
base=symget('test2');
|
||||||
|
result='NameXSexXAgeXHeightXWeight';
|
||||||
|
if base=result then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_comments="Comparing "!!trim(base)!!' vs '!!trim(result);
|
||||||
|
output;
|
||||||
|
|
||||||
|
test_description="DLM + quote test";
|
||||||
|
base=symget('test3');
|
||||||
|
result='"Name","Sex","Age","Height","Weight"';
|
||||||
|
if base=result then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_comments="Comparing "!!trim(base)!!' vs '!!trim(result);
|
||||||
|
output;
|
||||||
|
|
||||||
|
test_description="Numeric Filter";
|
||||||
|
base=symget('test4');
|
||||||
|
result='Age Height Weight';
|
||||||
|
if base=result then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_comments="Comparing "!!trim(base)!!' vs '!!trim(result);
|
||||||
|
output;
|
||||||
|
|
||||||
|
test_description="Char Filter";
|
||||||
|
base=symget('test5');
|
||||||
|
result='Name Sex';
|
||||||
|
if base=result then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_comments="Comparing "!!trim(base)!!' vs '!!trim(result);
|
||||||
|
output;
|
||||||
|
|
||||||
|
drop base result;
|
||||||
|
run;
|
||||||
32
tests/base/mp_assertcolvals.test.sas
Normal file
32
tests/base/mp_assertcolvals.test.sas
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_assertcolvals macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assertcolvals.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
data work.checkds;
|
||||||
|
do checkval='Jane','James','Jill';
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
%mp_assertcolvals(sashelp.class.name,
|
||||||
|
checkvals=work.checkds.checkval,
|
||||||
|
desc=At least one value has a match,
|
||||||
|
test=ANYVAL
|
||||||
|
)
|
||||||
|
|
||||||
|
data work.check;
|
||||||
|
do val='M','F';
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
%mp_assertcolvals(sashelp.class.sex,
|
||||||
|
checkvals=work.check.val,
|
||||||
|
desc=All values have a match,
|
||||||
|
test=ALLVALS
|
||||||
|
)
|
||||||
|
|
||||||
148
tests/base/mp_filtercheck.test.sas
Normal file
148
tests/base/mp_filtercheck.test.sas
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_filtercheck macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_filtercheck.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
/* valid filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,AGE,=,12
|
||||||
|
AND,AND,1,SEX,<=,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
|
||||||
|
AND,OR,2,Weight,>=,77.7
|
||||||
|
AND,OR,2,Weight,NE,77.7
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.badrecords,
|
||||||
|
desc=Valid filter query,
|
||||||
|
test=EMPTY,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* invalid column */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,invalid,=,12
|
||||||
|
AND,AND,1,SEX,<=,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
|
||||||
|
AND,OR,2,Weight,>=,7
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.badrecords,
|
||||||
|
desc=Invalid column name,
|
||||||
|
test=HASOBS,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* invalid raw value */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,OR,2,Name,NOT IN,"(''''Jane','Alfred')"
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.badrecords,
|
||||||
|
desc=Invalid raw value,
|
||||||
|
test=HASOBS,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Code injection - column name */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,%abort,=,12
|
||||||
|
AND,OR,2,Weight,>=,7
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.badrecords,
|
||||||
|
desc=Code injection - column name,
|
||||||
|
test=HASOBS,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Code injection - raw values*/
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,age,=,;;%abort
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.badrecords,
|
||||||
|
desc=Code injection - raw value abort,
|
||||||
|
test=HASOBS,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Supply variables with incorrect types */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:8;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,age,=,0
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_filtercheck(work.inds,
|
||||||
|
targetds=sashelp.class,
|
||||||
|
outds=work.badrecords,
|
||||||
|
abort=NO
|
||||||
|
)
|
||||||
|
%mp_assert(iftrue=(&syscc=42),
|
||||||
|
desc=Throw error if RAW_VALUE is incorrect,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%let syscc=0;
|
||||||
122
tests/base/mp_filtergenerate.test.sas
Normal file
122
tests/base/mp_filtergenerate.test.sas
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_filtergenerate macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_filtergenerate.sas
|
||||||
|
@li mp_filtercheck.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
options source2;
|
||||||
|
|
||||||
|
/* valid filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,AGE,>,5
|
||||||
|
AND,AND,1,SEX,NE,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Janet')"
|
||||||
|
AND,OR,2,Weight,>=,84.6
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,targetds=sashelp.class)
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
data work.test;
|
||||||
|
set sashelp.class;
|
||||||
|
where %inc myfilter;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test,
|
||||||
|
desc=Valid filter,
|
||||||
|
test=EQUALS 8,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* empty filter (return all records) */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,targetds=sashelp.class)
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
data work.test;
|
||||||
|
set sashelp.class;
|
||||||
|
where %inc myfilter;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test,
|
||||||
|
desc=Empty filter (return all records) ,
|
||||||
|
test=EQUALS 19,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* single line filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,OR,2,Name,IN,"('Jane','Janet')"
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,targetds=sashelp.class)
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
data work.test;
|
||||||
|
set sashelp.class;
|
||||||
|
where %inc myfilter;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test,
|
||||||
|
desc=Single line filter ,
|
||||||
|
test=EQUALS 2,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* single line 2 group filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
OR,OR,2,Name,IN,"('Jane','Janet')"
|
||||||
|
OR,OR,3,Name,IN,"('James')"
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,targetds=sashelp.class)
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
data work.test;
|
||||||
|
set sashelp.class;
|
||||||
|
where %inc myfilter;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test,
|
||||||
|
desc=Single line 2 group filter ,
|
||||||
|
test=EQUALS 3,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* filter with nothing returned */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,OR,2,Name,IN,"('Jane','Janet')"
|
||||||
|
AND,OR,3,Name,IN,"('James')"
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtercheck(work.inds,targetds=sashelp.class)
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
data work.test;
|
||||||
|
set sashelp.class;
|
||||||
|
where %inc myfilter;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test,
|
||||||
|
desc=Filter with nothing returned,
|
||||||
|
test=EQUALS 0,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
68
tests/base/mp_filtervalidate.test.sas
Normal file
68
tests/base/mp_filtervalidate.test.sas
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_filtervalidate macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_filtergenerate.sas
|
||||||
|
@li mp_filtervalidate.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
/* valid filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,AGE,>,5
|
||||||
|
AND,AND,1,SEX,NE,"'M'"
|
||||||
|
AND,OR,2,Name,NOT IN,"('Jane','Janet')"
|
||||||
|
AND,OR,2,Weight,>=,84.6
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
|
||||||
|
%mp_assertdsobs(work.results,
|
||||||
|
desc=Valid filter,
|
||||||
|
test=EMPTY,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* empty filter (return all records) */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
|
||||||
|
%mp_assertdsobs(work.results,
|
||||||
|
desc=Valid filter,
|
||||||
|
test=EMPTY,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* invalid filter*/
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,SEX,NE,2
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_filtergenerate(work.inds,outref=myfilter)
|
||||||
|
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
|
||||||
|
%let syscc=0;
|
||||||
|
%mp_assertdsobs(work.results,
|
||||||
|
desc=Valid filter,
|
||||||
|
test=EQUALS 1,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
62
tests/base/mp_validatecol.test.sas
Normal file
62
tests/base/mp_validatecol.test.sas
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_validatecol.sas macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
@li mp_validatecol.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 1 - LIBDS
|
||||||
|
*/
|
||||||
|
data test1;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input;
|
||||||
|
libds=_infile_;
|
||||||
|
%mp_validatecol(libds,LIBDS,is_libds)
|
||||||
|
if is_libds=1;
|
||||||
|
datalines4;
|
||||||
|
some.libname
|
||||||
|
!lib.blah
|
||||||
|
%abort
|
||||||
|
definite.ok
|
||||||
|
not.ok!
|
||||||
|
nineletrs._
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test1,
|
||||||
|
desc=Testing LIBDS,
|
||||||
|
test=EQUALS 2,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 2 - ISNUM
|
||||||
|
*/
|
||||||
|
data test2;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input;
|
||||||
|
infile=_infile_;
|
||||||
|
%mp_validatecol(infile,ISNUM,is_numeric)
|
||||||
|
if is_numeric=1;
|
||||||
|
datalines4;
|
||||||
|
1
|
||||||
|
0001
|
||||||
|
1e6
|
||||||
|
-44
|
||||||
|
above are good
|
||||||
|
the rest are bad
|
||||||
|
%abort
|
||||||
|
1&somethingverybad.
|
||||||
|
&
|
||||||
|
+-1
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.test2,
|
||||||
|
desc=Test2 - ISNUM,
|
||||||
|
test=EQUALS 4,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
8
tests/testinit.sas
Normal file
8
tests/testinit.sas
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief init file for tests
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
/* location in metadata or SAS Drive for temporary files */
|
||||||
|
%let mcTestAppLoc=/Public/temp/macrocore;
|
||||||
9
tests/testterm.sas
Normal file
9
tests/testterm.sas
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief term file for tests
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%webout(OPEN)
|
||||||
|
%webout(OBJ, TEST_RESULTS)
|
||||||
|
%webout(CLOSE)
|
||||||
45
tests/viya/mv_createwebservice.test.sas
Normal file
45
tests/viya/mv_createwebservice.test.sas
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mv_createwebservice macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mv_createwebservice.sas
|
||||||
|
@li mv_getjobcode.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Case 1
|
||||||
|
* Send special char in a service
|
||||||
|
*/
|
||||||
|
|
||||||
|
filename testref temp;
|
||||||
|
data _null_;
|
||||||
|
file testref;
|
||||||
|
put '01'x;
|
||||||
|
run;
|
||||||
|
%put TEST1: creating web service;
|
||||||
|
%mv_createwebservice(
|
||||||
|
path=&mcTestAppLoc/temp/macros,
|
||||||
|
name=mv_createwebservice,
|
||||||
|
code=testref
|
||||||
|
)
|
||||||
|
%put TEST1: fetching web service code;
|
||||||
|
%mv_getjobcode(
|
||||||
|
path=&mcTestAppLoc/temp/macros,
|
||||||
|
name=mv_createwebservice,
|
||||||
|
outref=compare
|
||||||
|
)
|
||||||
|
%put TEST1: checking web service code;
|
||||||
|
data work.test_results;
|
||||||
|
length test_description $256 test_result $4 test_comments $256;
|
||||||
|
infile compare end=eof;
|
||||||
|
input;
|
||||||
|
if eof then do;
|
||||||
|
if _infile_='01'x then test_result='PASS';
|
||||||
|
else test_result='FAIL';
|
||||||
|
test_description="Creating web service with invisible character";
|
||||||
|
output;
|
||||||
|
stop;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
49
tests/viya/mv_getjobcode.test.sas
Normal file
49
tests/viya/mv_getjobcode.test.sas
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mv_getjobcode macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mv_createjob.sas
|
||||||
|
@li mv_getjobcode.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Case 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* write some code to a job */
|
||||||
|
%let incode=%str(data test; set sashelp.class;run;);
|
||||||
|
filename testref temp;
|
||||||
|
data _null_;
|
||||||
|
file testref;
|
||||||
|
put "&incode";
|
||||||
|
run;
|
||||||
|
%mv_createjob(
|
||||||
|
code=testref,
|
||||||
|
path=&mcTestAppLoc/services/temp,
|
||||||
|
name=some_job
|
||||||
|
)
|
||||||
|
|
||||||
|
/* now get the code back */
|
||||||
|
%mv_getjobcode(
|
||||||
|
path=&mcTestAppLoc/services/temp,
|
||||||
|
name=some_job,
|
||||||
|
outref=mycode
|
||||||
|
)
|
||||||
|
|
||||||
|
%let diditexist=NO;
|
||||||
|
data work.test1;
|
||||||
|
infile mycode;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
line=_infile_;
|
||||||
|
check=symget('incode');
|
||||||
|
if _infile_=symget('incode') then call symputx('diditexist','YES');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&diditexist=NO),
|
||||||
|
desc=Check if the code that was sent was successfully retrieved
|
||||||
|
)
|
||||||
74
tests/viya/mv_getjobresult.test.sas
Normal file
74
tests/viya/mv_getjobresult.test.sas
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mv_createwebservice macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
@li mv_createwebservice.sas
|
||||||
|
@li mv_getjobresult.sas
|
||||||
|
@li mv_jobflow.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Case 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* create a service */
|
||||||
|
filename testref temp;
|
||||||
|
data _null_;
|
||||||
|
file testref;
|
||||||
|
put 'data test; set sashelp.class;run;';
|
||||||
|
put '%webout(OPEN)';
|
||||||
|
put '%webout(OBJ,test)';
|
||||||
|
put '%webout(CLOSE)';
|
||||||
|
run;
|
||||||
|
%mv_createwebservice(
|
||||||
|
path=&mcTestAppLoc/services/temp,
|
||||||
|
code=testref,
|
||||||
|
name=testsvc
|
||||||
|
)
|
||||||
|
|
||||||
|
/* trigger and wait for it to finish */
|
||||||
|
data work.inputjobs;
|
||||||
|
_program="&mcTestAppLoc/services/temp/testsvc";
|
||||||
|
run;
|
||||||
|
%mv_jobflow(inds=work.inputjobs
|
||||||
|
,maxconcurrency=4
|
||||||
|
,outds=work.results
|
||||||
|
,outref=myjoblog
|
||||||
|
)
|
||||||
|
/* stream the log */
|
||||||
|
data _null_;
|
||||||
|
infile myjoblog;
|
||||||
|
input;
|
||||||
|
put _infile_;
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* fetch the uri */
|
||||||
|
data _null_;
|
||||||
|
set work.results;
|
||||||
|
call symputx('uri',uri);
|
||||||
|
put (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* now get the results */
|
||||||
|
%mv_getjobresult(uri=&uri
|
||||||
|
,result=WEBOUT_JSON
|
||||||
|
,outref=myweb
|
||||||
|
,outlib=myweblib
|
||||||
|
)
|
||||||
|
data _null_;
|
||||||
|
infile myweb;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
data work.out;
|
||||||
|
set myweblib.test;
|
||||||
|
put (_all_)(=);
|
||||||
|
run;
|
||||||
|
%mp_assertdsobs(work.out,
|
||||||
|
desc=Test1 - 19 obs from sashelp.class in service result,
|
||||||
|
test=EQUALS 19,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
@param path= The full path of the folder to be created
|
@param path= The full path of the folder to be created
|
||||||
@param access_token_var= The global macro variable to contain the access token
|
@param access_token_var= The global macro variable to contain the access token
|
||||||
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
|
@param grant_type= (authorization_code) Valid values are "password" or
|
||||||
The default is authorization_code.
|
"authorization_code" (unquoted).
|
||||||
|
|
||||||
|
|
||||||
@version VIYA V.03.04
|
@version VIYA V.03.04
|
||||||
@@ -39,7 +39,6 @@
|
|||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
and &grant_type ne sas_services
|
and &grant_type ne sas_services
|
||||||
)
|
)
|
||||||
@@ -85,12 +84,15 @@ options noquotelenmax;
|
|||||||
%local libref1;
|
%local libref1;
|
||||||
%let libref1=%mf_getuniquelibref();
|
%let libref1=%mf_getuniquelibref();
|
||||||
libname &libref1 JSON fileref=&fname1;
|
libname &libref1 JSON fileref=&fname1;
|
||||||
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404)
|
%mp_abort(
|
||||||
|
iftrue=(
|
||||||
|
&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 404
|
||||||
|
)
|
||||||
,mac=&sysmacroname
|
,mac=&sysmacroname
|
||||||
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
)
|
)
|
||||||
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
|
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
|
||||||
%put &sysmacroname &newpath exists so grab the follow on link ;
|
%*put &sysmacroname &newpath exists so grab the follow on link ;
|
||||||
data _null_;
|
data _null_;
|
||||||
set &libref1..links;
|
set &libref1..links;
|
||||||
if rel='createChild' then
|
if rel='createChild' then
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5p
|
|||||||
%let oauth_bearer=oauth_bearer=sas_services;
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
|
|
||||||
/* initial validation checking */
|
/* initial validation checking */
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
|
|||||||
@@ -39,22 +39,26 @@
|
|||||||
@li mf_isblank.sas
|
@li mf_isblank.sas
|
||||||
@li mv_deletejes.sas
|
@li mv_deletejes.sas
|
||||||
|
|
||||||
@param path= The full path (on SAS Drive) where the service will be created
|
@param [in] path= The full path (on SAS Drive) where the service will be
|
||||||
@param name= The name of the service
|
created
|
||||||
@param desc= The description of the service
|
@param [in] name= The name of the service
|
||||||
@param precode= Space separated list of filerefs, pointing to the code that
|
@param [in] desc= The description of the service
|
||||||
needs to be attached to the beginning of the service
|
@param [in] precode= Space separated list of filerefs, pointing to the code
|
||||||
@param code= Fileref(s) of the actual code to be added
|
that needs to be attached to the beginning of the service
|
||||||
@param access_token_var= The global macro variable to contain the access token
|
@param [in] code= Fileref(s) of the actual code to be added
|
||||||
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
|
@param [in] access_token_var= The global macro variable to contain the access
|
||||||
The default is authorization_code.
|
token
|
||||||
@param replace= select NO to avoid replacing any existing service in that location
|
@param [in] grant_type= valid values are "password" or "authorization_code"
|
||||||
@param adapter= the macro uses the sasjs adapter by default. To use another
|
(unquoted). The default is authorization_code.
|
||||||
adapter, add a (different) fileref here.
|
@param [in] replace=(YES) Select NO to avoid replacing any existing service in
|
||||||
@param contextname= Choose a specific context on which to run the Job. Leave
|
that location
|
||||||
|
@param [in] adapter= the macro uses the sasjs adapter by default. To use
|
||||||
|
another adapter, add a (different) fileref here.
|
||||||
|
@param [in] contextname= Choose a specific context on which to run the Job. Leave
|
||||||
blank to use the default context. From Viya 3.5 it is possible to configure
|
blank to use the default context. From Viya 3.5 it is possible to configure
|
||||||
a shared context - see
|
a shared context - see
|
||||||
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
|
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
|
||||||
|
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
|
||||||
|
|
||||||
@version VIYA V.03.04
|
@version VIYA V.03.04
|
||||||
@author Allan Bowe, source: https://github.com/sasjs/core
|
@author Allan Bowe, source: https://github.com/sasjs/core
|
||||||
@@ -70,9 +74,17 @@ https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5p
|
|||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
,replace=YES
|
,replace=YES
|
||||||
,adapter=sasjs
|
,adapter=sasjs
|
||||||
,debug=0
|
,mdebug=0
|
||||||
,contextname=
|
,contextname=
|
||||||
|
,debug=0 /* @TODO - Deprecate */
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -82,7 +94,6 @@ https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5p
|
|||||||
%let oauth_bearer=oauth_bearer=sas_services;
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
|
|
||||||
/* initial validation checking */
|
/* initial validation checking */
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
@@ -126,7 +137,7 @@ proc http method='GET' out=&fname1 &oauth_bearer
|
|||||||
headers "Authorization"="Bearer &&&access_token_var";
|
headers "Authorization"="Bearer &&&access_token_var";
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
%if &debug %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
infile &fname1;
|
infile &fname1;
|
||||||
input;
|
input;
|
||||||
@@ -145,7 +156,8 @@ libname &libref1 JSON fileref=&fname1;
|
|||||||
|
|
||||||
data _null_;
|
data _null_;
|
||||||
set &libref1..links;
|
set &libref1..links;
|
||||||
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
|
if rel='members' then
|
||||||
|
call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
|
||||||
else if rel='self' then call symputx('parentFolderUri',href,'l');
|
else if rel='self' then call symputx('parentFolderUri',href,'l');
|
||||||
run;
|
run;
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -164,7 +176,7 @@ proc http method='GET'
|
|||||||
%end;
|
%end;
|
||||||
'Accept'='application/vnd.sas.collection+json'
|
'Accept'='application/vnd.sas.collection+json'
|
||||||
'Accept-Language'='string';
|
'Accept-Language'='string';
|
||||||
%if &debug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
debug level = 3;
|
debug level = 3;
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
@@ -219,9 +231,9 @@ run;
|
|||||||
* These put statements are auto generated - to change the macro, change the
|
* These put statements are auto generated - to change the macro, change the
|
||||||
* source (mv_webout) and run `build.py`
|
* source (mv_webout) and run `build.py`
|
||||||
*/
|
*/
|
||||||
filename sasjs temp lrecl=3000;
|
filename &adapter temp lrecl=3000;
|
||||||
data _null_;
|
data _null_;
|
||||||
file sasjs;
|
file &adapter;
|
||||||
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
|
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
|
||||||
/* WEBOUT BEGIN */
|
/* WEBOUT BEGIN */
|
||||||
put ' ';
|
put ' ';
|
||||||
@@ -560,11 +572,12 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
/* insert the code, escaping double quotes and carriage returns */
|
/* insert the code, escaping double quotes and carriage returns */
|
||||||
|
%&dbg.put &sysmacroname: Creating final input file;
|
||||||
%local x fref freflist;
|
%local x fref freflist;
|
||||||
%let freflist= &adapter &precode &code ;
|
%let freflist= &adapter &precode &code ;
|
||||||
%do x=1 %to %sysfunc(countw(&freflist));
|
%do x=1 %to %sysfunc(countw(&freflist));
|
||||||
%let fref=%scan(&freflist,&x);
|
%let fref=%scan(&freflist,&x);
|
||||||
%put &sysmacroname: adding &fref;
|
%&dbg.put &sysmacroname: adding &fref fileref;
|
||||||
data _null_;
|
data _null_;
|
||||||
length filein 8 fileid 8;
|
length filein 8 fileid 8;
|
||||||
filein = fopen("&fref","I",1,"B");
|
filein = fopen("&fref","I",1,"B");
|
||||||
@@ -592,6 +605,14 @@ run;
|
|||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
|
else if rec='01'x then do; /* Unprintable */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'u');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'0');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'0');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'0');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'1');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
else do;
|
else do;
|
||||||
rc =fput(fileid,rec);
|
rc =fput(fileid,rec);
|
||||||
rc =fwrite(fileid);
|
rc =fwrite(fileid);
|
||||||
@@ -608,7 +629,12 @@ data _null_;
|
|||||||
put '"}';
|
put '"}';
|
||||||
run;
|
run;
|
||||||
|
|
||||||
/* now we can create the job!! */
|
%if &mdebug=1 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then %do;
|
||||||
|
%put &sysmacroname: input about to be POSTed;
|
||||||
|
data _null_;infile &fname3;input;putlog _infile_;run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%&dbg.put &sysmacroname: Creating the actual service!;
|
||||||
%local fname4;
|
%local fname4;
|
||||||
%let fname4=%mf_getuniquefileref();
|
%let fname4=%mf_getuniquefileref();
|
||||||
proc http method='POST'
|
proc http method='POST'
|
||||||
@@ -621,22 +647,18 @@ proc http method='POST'
|
|||||||
"Authorization"="Bearer &&&access_token_var"
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
%end;
|
%end;
|
||||||
"Accept"="application/vnd.sas.job.definition+json";
|
"Accept"="application/vnd.sas.job.definition+json";
|
||||||
%if &debug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
debug level = 3;
|
debug level = 3;
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
/*data _null_;infile &fname4;input;putlog _infile_;run;*/
|
%if &mdebug=1 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then %do;
|
||||||
|
%put &sysmacroname: output from POSTing job definition;
|
||||||
|
data _null_;infile &fname4;input;putlog _infile_;run;
|
||||||
|
%end;
|
||||||
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||||
,mac=&sysmacroname
|
,mac=&sysmacroname
|
||||||
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
)
|
)
|
||||||
/* clear refs */
|
|
||||||
filename &fname1 clear;
|
|
||||||
filename &fname2 clear;
|
|
||||||
filename &fname3 clear;
|
|
||||||
filename &fname4 clear;
|
|
||||||
filename &adapter clear;
|
|
||||||
libname &libref1 clear;
|
|
||||||
|
|
||||||
/* get the url so we can give a helpful log message */
|
/* get the url so we can give a helpful log message */
|
||||||
%local url;
|
%local url;
|
||||||
@@ -651,6 +673,19 @@ data _null_;
|
|||||||
call symputx('url',url);
|
call symputx('url',url);
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
/* clear refs */
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
filename &fname3 clear;
|
||||||
|
filename &fname4 clear;
|
||||||
|
filename &adapter clear;
|
||||||
|
libname &libref1 clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
%put &sysmacroname: Job &name successfully created in &path;
|
%put &sysmacroname: Job &name successfully created in &path;
|
||||||
%put &sysmacroname:;
|
%put &sysmacroname:;
|
||||||
@@ -660,4 +695,4 @@ run;
|
|||||||
%put &sysmacroname:;
|
%put &sysmacroname:;
|
||||||
%put &sysmacroname:;
|
%put &sysmacroname:;
|
||||||
|
|
||||||
%mend;
|
%mend mv_createwebservice;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
%let oauth_bearer=oauth_bearer=sas_services;
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
and &grant_type ne sas_services
|
and &grant_type ne sas_services
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
%let oauth_bearer=oauth_bearer=sas_services;
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
and &grant_type ne sas_services
|
and &grant_type ne sas_services
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
%let oauth_bearer=oauth_bearer=sas_services;
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
%let &access_token_var=;
|
%let &access_token_var=;
|
||||||
%end;
|
%end;
|
||||||
%put &sysmacroname: grant_type=&grant_type;
|
|
||||||
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
and &grant_type ne sas_services
|
and &grant_type ne sas_services
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,17 +10,20 @@
|
|||||||
,outfile=/tmp/some_job.sas
|
,outfile=/tmp/some_job.sas
|
||||||
)
|
)
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access token
|
@param [in] access_token_var= The global macro variable to contain the access
|
||||||
|
token
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
* password
|
@li password
|
||||||
* authorization_code
|
@liauthorization_code
|
||||||
* detect - will check if access_token exists, if not will use sas_services if
|
@li detect - will check if access_token exists, if not will use sas_services
|
||||||
a SASStudioV session else authorization_code. Default option.
|
if a SASStudioV session else authorization_code. Default option.
|
||||||
* sas_services - will use oauth_bearer=sas_services
|
@li sas_services - will use oauth_bearer=sas_services
|
||||||
@param [in] path= The SAS Drive path of the job
|
@param [in] path= The SAS Drive path of the job
|
||||||
@param [in] name= The name of the job
|
@param [in] name= The name of the job
|
||||||
@param [out] outref= A fileref to which to write the source code
|
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
|
||||||
@param [out] outfile= A file to which to write the source code
|
@param [out] outref=(0) A fileref to which to write the source code (will be
|
||||||
|
created with a TEMP engine)
|
||||||
|
@param [out] outfile=(0) A file to which to write the source code
|
||||||
|
|
||||||
@version VIYA V.03.04
|
@version VIYA V.03.04
|
||||||
@author Allan Bowe, source: https://github.com/sasjs/core
|
@author Allan Bowe, source: https://github.com/sasjs/core
|
||||||
@@ -39,7 +42,15 @@
|
|||||||
,contextName=SAS Job Execution compute context
|
,contextName=SAS Job Execution compute context
|
||||||
,access_token_var=ACCESS_TOKEN
|
,access_token_var=ACCESS_TOKEN
|
||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
|
,mdebug=0
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -133,18 +144,30 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
%inc "&fpath3..lua";
|
%inc "&fpath3..lua";
|
||||||
/* export to desired destination */
|
/* export to desired destination */
|
||||||
|
%if "&outref"="0" %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
%if &outref=0 %then %do;
|
|
||||||
file "&outfile" lrecl=32767;
|
file "&outfile" lrecl=32767;
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
|
filename &outref temp;
|
||||||
|
data _null_;
|
||||||
file &outref;
|
file &outref;
|
||||||
%end;
|
%end;
|
||||||
infile &fname2;
|
infile &fname2;
|
||||||
input;
|
input;
|
||||||
put _infile_;
|
put _infile_;
|
||||||
|
&dbg. putlog _infile_;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
/* clear refs */
|
||||||
filename &fname1 clear;
|
filename &fname1 clear;
|
||||||
filename &fname2 clear;
|
filename &fname2 clear;
|
||||||
filename &fname3 clear;
|
filename &fname3 clear;
|
||||||
%mend;
|
%end;
|
||||||
|
|
||||||
|
%mend mv_getjobcode;
|
||||||
|
|||||||
@@ -54,13 +54,14 @@
|
|||||||
convenient way to wait for the job to finish before fetching the log.
|
convenient way to wait for the job to finish before fetching the log.
|
||||||
|
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access token
|
@param [in] access_token_var= The global macro variable to contain the access
|
||||||
|
token
|
||||||
@param [in] mdebug= set to 1 to enable DEBUG messages
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
@li password
|
@li password
|
||||||
@li authorization_code
|
@li authorization_code
|
||||||
@li detect - will check if access_token exists, if not will use sas_services if
|
@li detect - will check if access_token exists, if not will use sas_services
|
||||||
a SASStudioV session else authorization_code. Default option.
|
if a SASStudioV session else authorization_code. Default option.
|
||||||
@li sas_services - will use oauth_bearer=sas_services.
|
@li sas_services - will use oauth_bearer=sas_services.
|
||||||
@param [in] uri= The uri of the running job for which to fetch the status,
|
@param [in] uri= The uri of the running job for which to fetch the status,
|
||||||
in the format `/jobExecution/jobs/$UUID/state` (unquoted).
|
in the format `/jobExecution/jobs/$UUID/state` (unquoted).
|
||||||
@@ -85,6 +86,13 @@
|
|||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
,mdebug=0
|
,mdebug=0
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -260,9 +268,10 @@ run;
|
|||||||
filename &fname3 clear;
|
filename &fname3 clear;
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
%end;
|
%end;
|
||||||
%mend;
|
%mend mv_getjoblog;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
232
viya/mv_getjobresult.sas
Normal file
232
viya/mv_getjobresult.sas
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Extract the result from a completed SAS Viya Job
|
||||||
|
@details Extracts result from a Viya job and writes it out to a fileref
|
||||||
|
and/or a JSON-engine library.
|
||||||
|
|
||||||
|
To query the job, you need the URI. Sample code for achieving this
|
||||||
|
is provided below.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
First, compile the macros:
|
||||||
|
|
||||||
|
filename mc url
|
||||||
|
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
||||||
|
%inc mc;
|
||||||
|
|
||||||
|
Next, create a job (in this case, a web service):
|
||||||
|
|
||||||
|
filename ft15f001 temp;
|
||||||
|
parmcards4;
|
||||||
|
data test;
|
||||||
|
rand=ranuni(0)*1000;
|
||||||
|
do x=1 to rand;
|
||||||
|
y=rand*4;
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
proc sort data=&syslast
|
||||||
|
by descending y;
|
||||||
|
run;
|
||||||
|
%webout(OPEN)
|
||||||
|
%webout(OBJ, test)
|
||||||
|
%webout(CLOSE)
|
||||||
|
;;;;
|
||||||
|
%mv_createwebservice(path=/Public/temp,name=demo)
|
||||||
|
|
||||||
|
Execute it:
|
||||||
|
|
||||||
|
%mv_jobexecute(path=/Public/temp
|
||||||
|
,name=demo
|
||||||
|
,outds=work.info
|
||||||
|
)
|
||||||
|
|
||||||
|
Wait for it to finish, and grab the uri:
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
set work.info;
|
||||||
|
if method='GET' and rel='self';
|
||||||
|
call symputx('uri',uri);
|
||||||
|
run;
|
||||||
|
|
||||||
|
Finally, fetch the result (In this case, WEBOUT):
|
||||||
|
|
||||||
|
%mv_getjobresult(uri=&uri,result=WEBOUT_JSON,outref=myweb,outlib=myweblib)
|
||||||
|
|
||||||
|
|
||||||
|
@param [in] access_token_var= The global macro variable containing the access
|
||||||
|
token
|
||||||
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
|
@param [in] grant_type= valid values:
|
||||||
|
@li password
|
||||||
|
@li authorization_code
|
||||||
|
@li detect - will check if access_token exists, if not will use sas_services
|
||||||
|
if a SASStudioV session else authorization_code. Default option.
|
||||||
|
@li sas_services - will use oauth_bearer=sas_services.
|
||||||
|
@param [in] uri= The uri of the running job for which to fetch the status,
|
||||||
|
in the format `/jobExecution/jobs/$UUID` (unquoted).
|
||||||
|
|
||||||
|
@param [out] result= (WEBOUT_JSON) The result type to capture. Resolves
|
||||||
|
to "_[column name]" from the results table when parsed with the JSON libname
|
||||||
|
engine. Example values:
|
||||||
|
@li WEBOUT_JSON
|
||||||
|
@li WEBOUT_TXT
|
||||||
|
|
||||||
|
@param [out] outref= (0) The output fileref to which to write the results
|
||||||
|
@param [out] outlib= (0) The output library to which to assign the results
|
||||||
|
(assumes the data is in JSON format)
|
||||||
|
|
||||||
|
|
||||||
|
@version VIYA V.03.05
|
||||||
|
@author Allan Bowe, source: https://github.com/sasjs/core
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mp_binarycopy.sas
|
||||||
|
@li mf_getplatform.sas
|
||||||
|
@li mf_existfileref.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mv_getjobresult(uri=0
|
||||||
|
,contextName=SAS Job Execution compute context
|
||||||
|
,access_token_var=ACCESS_TOKEN
|
||||||
|
,grant_type=sas_services
|
||||||
|
,mdebug=0
|
||||||
|
,result=WEBOUT_JSON
|
||||||
|
,outref=0
|
||||||
|
,outlib=0
|
||||||
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
|
%local oauth_bearer;
|
||||||
|
%if &grant_type=detect %then %do;
|
||||||
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
|
%else %let grant_type=sas_services;
|
||||||
|
%end;
|
||||||
|
%if &grant_type=sas_services %then %do;
|
||||||
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
|
%let &access_token_var=;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
|
and &grant_type ne sas_services
|
||||||
|
)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Invalid value for grant_type: &grant_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* validation in datastep for better character safety */
|
||||||
|
%local errmsg errflg;
|
||||||
|
data _null_;
|
||||||
|
uri=symget('uri');
|
||||||
|
if length(uri)<12 then do;
|
||||||
|
call symputx('errflg',1);
|
||||||
|
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
|
||||||
|
end;
|
||||||
|
if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
|
||||||
|
call symputx('errflg',1);
|
||||||
|
call symputx('errmsg',
|
||||||
|
"URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
|
||||||
|
!!" but is actually like: &uri",'l');
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_abort(iftrue=(&errflg=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&errmsg)
|
||||||
|
)
|
||||||
|
|
||||||
|
%if &outref ne 0 and %mf_existfileref(&outref) ne 1 %then %do;
|
||||||
|
filename &outref temp;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
options noquotelenmax;
|
||||||
|
%local base_uri; /* location of rest apis */
|
||||||
|
%let base_uri=%mf_getplatform(VIYARESTAPI);
|
||||||
|
|
||||||
|
/* fetch job info */
|
||||||
|
%local fname1;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
proc http method='GET' out=&fname1 &oauth_bearer
|
||||||
|
url="&base_uri&uri";
|
||||||
|
headers "Accept"="application/json"
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
;
|
||||||
|
run;
|
||||||
|
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
|
||||||
|
%do;
|
||||||
|
data _null_;infile &fname1;input;putlog _infile_;run;
|
||||||
|
%mp_abort(mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
%end;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
data _null_;
|
||||||
|
infile &fname1 lrecl=32767;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* extract results link */
|
||||||
|
%local lib1 resuri;
|
||||||
|
%let lib1=%mf_getuniquelibref();
|
||||||
|
libname &lib1 JSON fileref=&fname1;
|
||||||
|
data _null_;
|
||||||
|
set &lib1..results;
|
||||||
|
call symputx('resuri',_&result,'l');
|
||||||
|
&dbg putlog "&sysmacroname results: " (_all_)(=);
|
||||||
|
run;
|
||||||
|
%mp_abort(iftrue=("&resuri"=".")
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Variable _&result did not exist in the response json)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* extract results */
|
||||||
|
%local fname2;
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
proc http method='GET' out=&fname2 &oauth_bearer
|
||||||
|
url="&base_uri&resuri/content?limit=10000";
|
||||||
|
headers "Accept"="application/json"
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
;
|
||||||
|
run;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
data _null_;
|
||||||
|
infile &fname2 lrecl=32767;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%if &outref ne 0 %then %do;
|
||||||
|
filename &outref temp;
|
||||||
|
%mp_binarycopy(inref=&fname2,outref=&outref)
|
||||||
|
%end;
|
||||||
|
%if &outlib ne 0 %then %do;
|
||||||
|
libname &outlib JSON fileref=&fname2;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%if &mdebug=0 %then %do;
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
libname &lib1 clear;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend mv_getjobresult;
|
||||||
@@ -23,24 +23,25 @@
|
|||||||
,paramstring=%str("macvarname":"macvarvalue","answer":42)
|
,paramstring=%str("macvarname":"macvarvalue","answer":42)
|
||||||
)
|
)
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access token
|
@param [in] access_token_var= The global macro variable to contain the access
|
||||||
|
token
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
|
@li password
|
||||||
* password
|
@li authorization_code
|
||||||
* authorization_code
|
@li detect - will check if access_token exists, if not will use sas_services
|
||||||
* detect - will check if access_token exists, if not will use sas_services if
|
if a SASStudioV session else authorization_code. Default option.
|
||||||
a SASStudioV session else authorization_code. Default option.
|
@li sas_services - will use oauth_bearer=sas_services
|
||||||
* sas_services - will use oauth_bearer=sas_services
|
|
||||||
|
|
||||||
@param [in] path= The SAS Drive path to the job being executed
|
@param [in] path= The SAS Drive path to the job being executed
|
||||||
@param [in] name= The name of the job to execute
|
@param [in] name= The name of the job to execute
|
||||||
@param [in] paramstring= A JSON fragment with name:value pairs, eg: `"name":"value"`
|
@param [in] paramstring= A JSON fragment with name:value pairs, eg:
|
||||||
or "name":"value","name2":42`. This will need to be wrapped in `%str()`.
|
`"name":"value"` or "name":"value","name2":42`. This will need to be
|
||||||
|
wrapped in `%str()`.
|
||||||
|
|
||||||
@param [in] contextName= Context name with which to run the job.
|
@param [in] contextName= Context name with which to run the job.
|
||||||
Default = `SAS Job Execution compute context`
|
Default = `SAS Job Execution compute context`
|
||||||
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
@param [out] outds= The output dataset containing links (Default=work.mv_jobexecute)
|
@param [out] outds= (work.mv_jobexecute) The output dataset containing links
|
||||||
|
|
||||||
|
|
||||||
@version VIYA V.03.04
|
@version VIYA V.03.04
|
||||||
@@ -62,7 +63,15 @@
|
|||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
,paramstring=0
|
,paramstring=0
|
||||||
,outds=work.mv_jobexecute
|
,outds=work.mv_jobexecute
|
||||||
|
,mdebug=0
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -164,9 +173,14 @@ data &outds;
|
|||||||
_program="&path/&name";
|
_program="&path/&name";
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
/* clear refs */
|
/* clear refs */
|
||||||
filename &fname0 clear;
|
filename &fname0 clear;
|
||||||
filename &fname1 clear;
|
filename &fname1 clear;
|
||||||
libname &libref;
|
libname &libref;
|
||||||
|
%end;
|
||||||
%mend;
|
%mend mv_jobexecute;
|
||||||
@@ -136,6 +136,13 @@
|
|||||||
,raise_err=0
|
,raise_err=0
|
||||||
,mdebug=0
|
,mdebug=0
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -293,6 +300,7 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
,name=&jobname
|
,name=&jobname
|
||||||
,paramstring=%superq(jparams&jid)
|
,paramstring=%superq(jparams&jid)
|
||||||
,outds=&jdsapp
|
,outds=&jdsapp
|
||||||
|
,mdebug=&mdebug
|
||||||
)
|
)
|
||||||
data &jdsapp;
|
data &jdsapp;
|
||||||
format jobparams $32767.;
|
format jobparams $32767.;
|
||||||
@@ -313,8 +321,13 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
%end;
|
%end;
|
||||||
%if &jid=&jcnt %then %do;
|
%if &jid=&jcnt %then %do;
|
||||||
/* we are at the end of the loop - time to see which jobs have finished */
|
/* we are at the end of the loop - time to see which jobs have finished */
|
||||||
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref
|
%mv_jobwaitfor(ANY
|
||||||
,raise_err=&raise_err)
|
,inds=&jdsrunning
|
||||||
|
,outds=&jdswaitfor
|
||||||
|
,outref=&outref
|
||||||
|
,raise_err=&raise_err
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
%local done;
|
%local done;
|
||||||
%let done=%mf_nobs(&jdswaitfor);
|
%let done=%mf_nobs(&jdswaitfor);
|
||||||
%if &done>0 %then %do;
|
%if &done>0 %then %do;
|
||||||
@@ -346,7 +359,8 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &mdebug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend;
|
%mend mv_jobflow;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Takes a dataset of running jobs and waits for ANY or ALL of them to complete
|
@brief Takes a table of running jobs and waits for ANY/ALL of them to complete
|
||||||
@details Will poll `/jobs/{jobId}/state` at set intervals until ANY or ALL
|
@details Will poll `/jobs/{jobId}/state` at set intervals until ANY or ALL
|
||||||
jobs are completed. Completion is determined by reference to the returned
|
jobs are completed. Completion is determined by reference to the returned
|
||||||
_state_, as per the following table:
|
_state_, as per the following table:
|
||||||
@@ -55,13 +55,14 @@
|
|||||||
|
|
||||||
%mv_deletejes(path=/Public/temp,name=demo)
|
%mv_deletejes(path=/Public/temp,name=demo)
|
||||||
|
|
||||||
@param [in] access_token_var= The global macro variable to contain the access token
|
@param [in] access_token_var= The global macro variable to contain the access
|
||||||
|
token
|
||||||
@param [in] grant_type= valid values:
|
@param [in] grant_type= valid values:
|
||||||
|
|
||||||
- password
|
- password
|
||||||
- authorization_code
|
- authorization_code
|
||||||
- detect - will check if access_token exists, if not will use sas_services if
|
- detect - will check if access_token exists, if not will use sas_services
|
||||||
a SASStudioV session else authorization_code. Default option.
|
if a SASStudioV session else authorization_code. Default option.
|
||||||
- sas_services - will use oauth_bearer=sas_services
|
- sas_services - will use oauth_bearer=sas_services
|
||||||
|
|
||||||
@param [in] action=Either ALL (to wait for every job) or ANY (if one job
|
@param [in] action=Either ALL (to wait for every job) or ANY (if one job
|
||||||
@@ -72,9 +73,11 @@
|
|||||||
should be in a `_program` variable.
|
should be in a `_program` variable.
|
||||||
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
||||||
succcessfully
|
succcessfully
|
||||||
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
@param [out] outds= The output dataset containing the list of states by job
|
@param [out] outds= The output dataset containing the list of states by job
|
||||||
(default=work.mv_jobexecute)
|
(default=work.mv_jobexecute)
|
||||||
@param [out] outref= A fileref to which the spawned job logs should be appended.
|
@param [out] outref= A fileref to which the spawned job logs should be
|
||||||
|
appended.
|
||||||
|
|
||||||
@version VIYA V.03.04
|
@version VIYA V.03.04
|
||||||
@author Allan Bowe, source: https://github.com/sasjs/core
|
@author Allan Bowe, source: https://github.com/sasjs/core
|
||||||
@@ -97,7 +100,15 @@
|
|||||||
,outds=work.mv_jobwaitfor
|
,outds=work.mv_jobwaitfor
|
||||||
,outref=0
|
,outref=0
|
||||||
,raise_err=0
|
,raise_err=0
|
||||||
|
,mdebug=0
|
||||||
);
|
);
|
||||||
|
%local dbg;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
@@ -155,7 +166,8 @@ run;
|
|||||||
%let fname0=%mf_getuniquefileref();
|
%let fname0=%mf_getuniquefileref();
|
||||||
|
|
||||||
data &outds;
|
data &outds;
|
||||||
format _program uri $128. state $32. stateDetails $32. timestamp datetime19. jobparams $32767.;
|
format _program uri $128. state $32. stateDetails $32. timestamp datetime19.
|
||||||
|
jobparams $32767.;
|
||||||
stop;
|
stop;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -168,8 +180,8 @@ run;
|
|||||||
"Authorization"="Bearer &&&access_token_var"
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
%end; ;
|
%end; ;
|
||||||
run;
|
run;
|
||||||
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
|
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
|
||||||
%do;
|
%then %do;
|
||||||
data _null_;infile &fname0;input;putlog _infile_;run;
|
data _null_;infile &fname0;input;putlog _infile_;run;
|
||||||
%mp_abort(mac=&sysmacroname
|
%mp_abort(mac=&sysmacroname
|
||||||
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
@@ -205,7 +217,7 @@ run;
|
|||||||
%let joburi&i=0; /* do not re-check */
|
%let joburi&i=0; /* do not re-check */
|
||||||
/* fetch log */
|
/* fetch log */
|
||||||
%if %str(&outref) ne 0 %then %do;
|
%if %str(&outref) ne 0 %then %do;
|
||||||
%mv_getjoblog(uri=&plainuri,outref=&outref)
|
%mv_getjoblog(uri=&plainuri,outref=&outref,mdebug=&mdebug)
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &status=idle or &status=pending or &status=running %then %do;
|
%else %if &status=idle or &status=pending or &status=running %then %do;
|
||||||
@@ -220,10 +232,11 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if (&raise_err) %then %do;
|
%if (&raise_err) %then %do;
|
||||||
%if (&status = canceled or &status = failed or %length(&stateDetails)>0) %then %do;
|
%if (&status = canceled or &status = failed or %length(&stateDetails)>0)
|
||||||
|
%then %do;
|
||||||
%if ("&stateDetails" = "%str(war)ning") %then %let SYSCC=4;
|
%if ("&stateDetails" = "%str(war)ning") %then %let SYSCC=4;
|
||||||
%else %let SYSCC=5;
|
%else %let SYSCC=5;
|
||||||
%put %str(ERR)OR: Job &&jobname&i. did not complete successfully. &stateDetails;
|
%put %str(ERR)OR: Job &&jobname&i. did not complete. &stateDetails;
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
@@ -238,7 +251,12 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
/* clear refs */
|
/* clear refs */
|
||||||
filename &fname0 clear;
|
filename &fname0 clear;
|
||||||
|
%end;
|
||||||
%mend;
|
%mend mv_jobwaitfor;
|
||||||
Reference in New Issue
Block a user