1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-05 00:20:05 +00:00

Compare commits

..

18 Commits

Author SHA1 Message Date
Allan Bowe
4c1f69da3a fix: using PROC JSON for JSON where SYSENCODING=wlatin1 2021-06-01 18:24:04 +03:00
Allan Bowe
f160ebe705 chore: updating all.sas from previous pushes 2021-06-01 18:01:01 +03:00
Allan Bowe
53ed5dc916 fix: adding extra debugging to mf_getvarlist 2021-06-01 09:32:19 +03:00
Allan Bowe
808b24e31b chore: adding mend statement 2021-05-31 15:15:17 +03:00
Allan Bowe
4d6edf5566 feat: additional options for mv_createfile.sas, also a log message to enable file to be easily opened 2021-05-30 13:22:50 +03:00
Allan Bowe
41a24677f5 chore: automated commit 2021-05-27 09:42:15 +03:00
Allan Bowe
e7d8d8ffb3 chore: updating docs 2021-05-27 09:40:38 +03:00
Allan Bowe
60d23dd618 Merge pull request #39 from sasjs/newviyafeatures
Newviyafeatures
2021-05-27 00:31:44 +03:00
Allan Bowe
d2764c3cd1 chore: updating all.sas 2021-05-26 23:37:38 +03:00
Allan Bowe
f9f4355143 feat: adding mv_createfile.sas and tests 2021-05-26 23:37:24 +03:00
Allan Bowe
18bc6c889d feat: adding mfv_existfolder.sas and tests 2021-05-26 23:37:06 +03:00
Allan Bowe
42a16ef496 feat: adding mfv_existfile.sas and tests 2021-05-26 23:36:43 +03:00
Allan Bowe
8178b801fb fix: using mfv_existfolder macro in mv_createfolder to save requests 2021-05-26 23:36:09 +03:00
Allan Bowe
ce331a23c8 fix: ensuring obs is updated when the table has zero columns 2021-05-26 23:35:25 +03:00
Allan Bowe
1cc9213467 feat: refreshing mf_abort (it's now an actual macro function) 2021-05-26 23:34:43 +03:00
Allan Bowe
aabbf4d0f9 Merge pull request #38 from sasjs/weboutfixes
fix: changing replace to YES in mm_createwebservice.sas, also setting…
2021-05-26 18:29:08 +03:00
Allan Bowe
2bea8be70d chore: logging in test 2021-05-26 18:19:04 +03:00
Allan Bowe
9b2368443e fix: changing replace to YES in mm_createwebservice.sas, also setting a default for code to ft15f001. More debugging added to mv_createfolder.sas 2021-05-26 10:36:45 +03:00
19 changed files with 731 additions and 319 deletions

View File

@@ -6,7 +6,7 @@
"hasMacroParentheses": true, "hasMacroParentheses": true,
"noNestedMacros": false, "noNestedMacros": false,
"noSpacesInFileNames": true, "noSpacesInFileNames": true,
"maxLineLength": 135, "maxLineLength": 230,
"lowerCaseFileNames": true, "lowerCaseFileNames": true,
"noTabIndentation": true, "noTabIndentation": true,
"indentationMultiple": 2 "indentationMultiple": 2

466
all.sas
View File

@@ -18,19 +18,18 @@
options noquotelenmax; options noquotelenmax;
/** /**
@file @file
@brief to be deprecated @brief Abort, ungracefully
@details We will deprecate this macro in 2022 @details Will abort with a straightforward %abort if the condition is true.
As you can see, it's not a macro function. <h4> Related Macros </h4>
@li mp_abort.sas
Use mp_abort.sas instead.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@cond @cond
**/ **/
%macro mf_abort(mac=mf_abort.sas, type=, msg=, iftrue=%str(1=1) %macro mf_abort(mac=mf_abort.sas, type=deprecated, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %if not(%eval(%unquote(&iftrue))) %then %return;
@@ -39,117 +38,9 @@ options noquotelenmax;
%if %length(&mac)>0 %then %put NOTE- called by &mac; %if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg; %put NOTE - &msg;
/* Stored Process Server web app context */ %abort;
%if %symexist(_metaperson) or "&SYSPROCESSNAME"="Compute Server" %then %do;
options obs=max replace nosyntaxcheck mprint;
/* extract log err / warn, if exist */
%local logloc logline;
%global logmsg; /* capture global messages */
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0;
data _null_;
infile &logloc lrecl=5000;
input; putlog _infile_;
i=1;
retain logonce 0;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0
then do;
call symputx('logline',_n_);
logonce+1;
end;
run;
/* capture log including lines BEFORE the err */
%if &logline>0 %then %do;
data _null_;
infile &logloc lrecl=5000;
input;
i=1;
stoploop=0;
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
input;
i+1;
stoploop=1;
end;
if stoploop=1 then stop;
run;
%end;
%end;
/* send response in SASjs JSON format */ %mend mf_abort;
data _null_;
file _webout mod lrecl=32000;
length msg $32767;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */
msg=compress(msg,,'kw');
/* quote without quoting the quotes (which are escaped instead) */
msg=cats('"',msg,'"');
if symexist('_debug') then debug=symget('_debug');
if debug ge 131 then put '>>weboutBEGIN<<';
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
put ',"sasjsAbort" : [{';
put ' "MSG":' msg ;
put ' ,"MAC": "' "&mac" '"}]';
put ",""SYSUSERID"" : ""&sysuserid"" ";
if symexist('_metauser') then do;
_METAUSER=quote(trim(symget('_METAUSER')));
put ",""_METAUSER"": " _METAUSER;
_METAPERSON=quote(trim(symget('_METAPERSON')));
put ',"_METAPERSON": ' _METAPERSON;
end;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
%if &_debug ge 131 %then %do;
put '>>weboutEND<<';
%end;
run;
%let syscc=0;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json";
%let rc=%sysfunc(fcopy(_web,_webout));
%end;
%else %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;
file skip;
put '%macro skip(); %macro skippy();';
run;
%inc skip;
%end;
%else %do;
%put _all_;
%abort cancel;
%end;
%mend;
/** @endcond *//** /** @endcond *//**
@file mf_existds.sas @file mf_existds.sas
@@ -176,7 +67,8 @@ options noquotelenmax;
%if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0; %if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0;
%else 1; %else 1;
%mend;/** %mend mf_existds;
/**
@file @file
@brief Checks whether a feature exists @brief Checks whether a feature exists
@details Check to see if a feature is supported in your environment. @details Check to see if a feature is supported in your environment.
@@ -1084,7 +976,8 @@ options noquotelenmax;
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
%else %do; %else %do;
%put unable to open &libds (rc=&dsid); %put &sysmacroname: Unable to open &libds (rc=&dsid);
%put &sysmacroname: SYSMSG= %sysfunc(sysmsg());
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
&outvar &outvar
@@ -5149,7 +5042,8 @@ create table &outds (rename=(
%let fmtds=%scan(&syslast,2,.); %let fmtds=%scan(&syslast,2,.);
/* prepare formats and varnames */ /* prepare formats and varnames */
data _null_; data _null_;
set &fmtds end=last; if _n_=1 then call symputx('nobs',nobs,'l');
set &fmtds end=last nobs=nobs;
name=upcase(name); name=upcase(name);
/* fix formats */ /* fix formats */
if type=2 or type=6 then do; if type=2 or type=6 then do;
@@ -5175,7 +5069,6 @@ create table &outds (rename=(
call symputx(cats('len',_n_),newlen,'l'); call symputx(cats('len',_n_),newlen,'l');
call symputx(cats('fmt',_n_),fmt,'l'); call symputx(cats('fmt',_n_),fmt,'l');
call symputx(cats('type',_n_),type,'l'); call symputx(cats('type',_n_),type,'l');
if last then call symputx('nobs',_n_,'l');
run; run;
data &fmtds; data &fmtds;
/* rename on entry */ /* rename on entry */
@@ -8901,7 +8794,7 @@ Usage:
%webout(OBJ,example2) * Object format, easier to work with ; %webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE) %webout(CLOSE)
;;;; ;;;;
%mm_createwebservice(path=/Public/app/common,name=appInit) %mm_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mm_createstp.sas @li mm_createstp.sas
@@ -8916,12 +8809,15 @@ Usage:
@param desc= The description of the service (optional) @param desc= The description of the service (optional)
@param precode= Space separated list of filerefs, pointing to the code that @param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the service (optional) needs to be attached to the beginning of the service (optional)
@param code= Space seperated fileref(s) of the actual code to be added @param code=(ft15f001) Space seperated fileref(s) of the actual code to be
@param server= The server which will run the STP. Server name or uri is fine. added
@param mDebug= set to 1 to show debug messages in the log @param server=(SASApp) The server which will run the STP. Server name or uri
@param replace= select YES to replace any existing service in that location is fine.
@param adapter= the macro uses the sasjs adapter by default. To use another @param mDebug=(0) set to 1 to show debug messages in the log
adapter, add a (different) fileref here. @param replace=(YES) select NO to avoid replacing an existing service in that
location
@param adapter=(sasjs) the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@@ -8931,11 +8827,11 @@ Usage:
%macro mm_createwebservice(path= %macro mm_createwebservice(path=
,name=initService ,name=initService
,precode= ,precode=
,code= ,code=ft15f001
,desc=This stp was created automagically by the mm_createwebservice macro ,desc=This stp was created automagically by the mm_createwebservice macro
,mDebug=0 ,mDebug=0
,server=SASApp ,server=SASApp
,replace=NO ,replace=YES
,adapter=sasjs ,adapter=sasjs
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -9010,7 +8906,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); '; put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ '; put ' /* prepare formats and varnames */ ';
put ' data _null_; '; put ' data _null_; ';
put ' set &fmtds end=last; '; put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); '; put ' name=upcase(name); ';
put ' /* fix formats */ '; put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; '; put ' if type=2 or type=6 then do; ';
@@ -9036,7 +8933,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; '; put ' run; ';
put ' data &fmtds; '; put ' data &fmtds; ';
put ' /* rename on entry */ '; put ' /* rename on entry */ ';
@@ -9142,7 +9038,12 @@ data _null_;
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); '; put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug '; put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; '; put ' sasjs_tables; ';
put '%local i tempds; '; put '%local i tempds jsonengine; ';
put ' ';
put '/* see https://github.com/sasjs/core/issues/41 */ ';
put '%if %upcase(&SYSENCODING)=WLATIN1 %then %let jsonengine=PROCJSON; ';
put '%else %let jsonengine=DATASTEP; ';
put ' ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
put ' %if %str(&_debug) ge 131 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
@@ -9177,7 +9078,7 @@ data _null_;
put ' OPTIONS NOBOMFILE; '; put ' OPTIONS NOBOMFILE; ';
put ' '; put ' ';
put ' /** '; put ' /** ';
put ' * check engine type to avoid the below err message: '; put ' * check xengine type to avoid the below err message: ';
put ' * > Function is only valid for filerefs using the CACHE access method. '; put ' * > Function is only valid for filerefs using the CACHE access method. ';
put ' */ '; put ' */ ';
put ' data _null_; '; put ' data _null_; ';
@@ -9199,7 +9100,7 @@ data _null_;
put ' '; put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,dbg=%str(&_debug) '; put ' ,engine=&jsonengine,dbg=%str(&_debug) ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -9212,7 +9113,7 @@ data _null_;
put ' %local wtcnt;%let wtcnt=0; '; put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; '; put ' data _null_; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if not (name =:"DATA"); '; put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
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''); ';
@@ -9232,8 +9133,8 @@ data _null_;
put ' put " ""&wt"" : {"; '; put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; '; put ' put ''"nlobs":'' nlobs; ';
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=&jsonengine) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) '; put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine) ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' %end; '; put ' %end; ';
@@ -9347,7 +9248,7 @@ run;
%put &url?_PROGRAM=&path/&name; %put &url?_PROGRAM=&path/&name;
%put ;%put ;%put ;%put ;%put ;%put ; %put ;%put ;%put ;%put ;%put ;%put ;
%mend; %mend mm_createwebservice;
/** /**
@file mm_deletedocument.sas @file mm_deletedocument.sas
@brief Deletes a Document using path as reference @brief Deletes a Document using path as reference
@@ -12628,7 +12529,12 @@ run;
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
%local i tempds; %local i tempds jsonengine;
/* see https://github.com/sasjs/core/issues/41 */
%if %upcase(&SYSENCODING)=WLATIN1 %then %let jsonengine=PROCJSON;
%else %let jsonengine=DATASTEP;
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
%if %str(&_debug) ge 131 %then %do; %if %str(&_debug) ge 131 %then %do;
@@ -12663,7 +12569,7 @@ run;
OPTIONS NOBOMFILE; OPTIONS NOBOMFILE;
/** /**
* check engine type to avoid the below err message: * check xengine type to avoid the below err message:
* > Function is only valid for filerefs using the CACHE access method. * > Function is only valid for filerefs using the CACHE access method.
*/ */
data _null_; data _null_;
@@ -12685,7 +12591,7 @@ run;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug) ,engine=&jsonengine,dbg=%str(&_debug)
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
@@ -12698,7 +12604,7 @@ run;
%local wtcnt;%let wtcnt=0; %local wtcnt;%let wtcnt=0;
data _null_; data _null_;
set &tempds; set &tempds;
if not (name =:"DATA"); if not (upcase(name) =:"DATA"); /* ignore temp datasets */
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');
@@ -12718,8 +12624,8 @@ run;
put " ""&wt"" : {"; put " ""&wt"" : {";
put '"nlobs":' nlobs; put '"nlobs":' nlobs;
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=&jsonengine)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine)
data _null_; file &fref mod encoding='utf-8'; data _null_; file &fref mod encoding='utf-8';
put "}"; put "}";
%end; %end;
@@ -12887,19 +12793,233 @@ run;
%inc &fref1; %inc &fref1;
%mend;/** %mend;/**
@file
@brief Checks whether a file exists in SAS Drive
@details Returns 1 if the file exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfile(/does/exist.txt);
%put %mfv_existfile(/does/not/exist.txt);
@param filepath The full path to the file on SAS drive (eg /Public/myfile.txt)
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfolder.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfile(filepath
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfile.sas with syscc=&syscc
)
%local fref rc path name;
%let fref=%mf_getuniquefileref();
%let name=%scan(&filepath,-1,/);
%let path=%substr(&filepath,1,%length(&filepath)-%length(&name)-1);
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path" filename="&name"))=0
%then %do;
%sysfunc(fexist(&fref))
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfile;/**
@file
@brief Checks whether a folder exists in SAS Drive
@details Returns 1 if the folder exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfolder(/does/exist);
%put %mfv_existfolder(/does/not/exist);
@param path The path to the folder on SAS drive
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfile.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfolder(path
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfolder.sas with syscc=&syscc
)
%local fref rc;
%let fref=%mf_getuniquefileref();
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do;
1
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfolder;/**
@file
@brief Creates a file in SAS Drive
@details Creates a file in SAS Drive and adds the appropriate content type.
If the parent folder does not exist, it is created.
Usage:
filename myfile temp;
data _null_;
file myfile;
put 'something';
run;
%mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile)
@param [in] path= The parent folder in which to create the file
@param [in] name= The name of the file to be created
@param [in] inref= The fileref pointing to the file to be uploaded
@param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline
@li attachment
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mv_createfolder.sas
**/
%macro mv_createfile(path=
,name=
,inref=
,contentdisp=inline
,access_token_var=ACCESS_TOKEN
,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;
%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)
)
%mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1)
,mac=&sysmacroname
,msg=%str(path value must be provided)
)
%mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1)
,mac=&sysmacroname
,msg=%str(name value with length >1 must be provided)
)
/* create folder if it does not already exist */
%mv_createfolder(path=&path
,access_token_var=&access_token_var
,grant_type=&grant_type
,mdebug=&mdebug
)
/* create file with relevant options */
%local fref;
%let fref=%mf_getuniquefileref();
filename &fref filesrvc
folderPath="&path"
filename="&name"
cdisp="&contentdisp";
%mp_binarycopy(inref=&inref, outref=&fref)
filename &fref clear;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%put &sysmacroname: File &name successfully created in &path;
%put &sysmacroname:;%put;
%put &base_uri/SASJobExecution?_file=&path/&name;%put;
%put &sysmacroname:;
%mend mv_createfile;/**
@file mv_createfolder.sas @file mv_createfolder.sas
@brief Creates a viya folder if that folder does not already exist @brief Creates a viya folder if that folder does not already exist
@details Expects oauth token in a global macro variable (default @details Creates a viya folder by checking if each parent folder exists, and
ACCESS_TOKEN). recursively creating children if needed.
Usage:
%mv_createfolder(path=/Public) %mv_createfolder(path=/Public)
@param path= The full path of the folder to be created @param [in] path= The full path of the folder to be created
@param 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
@param grant_type= (authorization_code) Valid values are "password" or token, if using authorization_code grant type.
"authorization_code" (unquoted). @param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@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
@@ -12910,21 +13030,36 @@ run;
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas
@li mf_isblank.sas @li mf_isblank.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mfv_existfolder.sas
**/ **/
%macro mv_createfolder(path= %macro mv_createfolder(path=
,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=*;
%if %mfv_existfolder(&path)=1 %then %do;
%put &sysmacroname: &path already exists;
%return;
%end;
%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;
%else %let grant_type=sas_services; %else %let grant_type=sas_services;
%end; %end;
%if &grant_type=sas_services %then %do; %if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services; %let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=; %let &access_token_var=;
%end; %end;
%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
@@ -12979,6 +13114,15 @@ options noquotelenmax;
,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 &mdebug=1 %then %do;
%put &sysmacroname following check to see if &newpath exists:;
%put _local_;
data _null_;
set &fname1;
input;
putlog _infile_;
run;
%end;
%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_;
@@ -13028,8 +13172,10 @@ options noquotelenmax;
%put &sysmacroname &newpath now created. Grabbing the follow on link ; %put &sysmacroname &newpath now created. Grabbing the follow on link ;
data _null_; data _null_;
set &libref2..links; set &libref2..links;
if rel='createChild' then if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l'); call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=);
end;
run; run;
libname &libref2 clear; libname &libref2 clear;
@@ -13629,7 +13775,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); '; put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ '; put ' /* prepare formats and varnames */ ';
put ' data _null_; '; put ' data _null_; ';
put ' set &fmtds end=last; '; put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); '; put ' name=upcase(name); ';
put ' /* fix formats */ '; put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; '; put ' if type=2 or type=6 then do; ';
@@ -13655,7 +13802,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; '; put ' run; ';
put ' data &fmtds; '; put ' data &fmtds; ';
put ' /* rename on entry */ '; put ' /* rename on entry */ ';
@@ -13896,8 +14042,9 @@ data _null_;
put ' ods output Members=&tempds; '; put ' ods output Members=&tempds; ';
put ' proc datasets library=WORK memtype=data; '; put ' proc datasets library=WORK memtype=data; ';
put ' %local wtcnt;%let wtcnt=0; '; put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; set &tempds; '; put ' data _null_; ';
put ' if not (name =:"DATA"); '; put ' set &tempds; ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; '; put ' i+1; ';
put ' call symputx(''wt''!!left(i),name); '; put ' call symputx(''wt''!!left(i),name); ';
put ' call symputx(''wtcnt'',i); '; put ' call symputx(''wtcnt'',i); ';
@@ -17696,8 +17843,9 @@ filename &fref1 clear;
ods output Members=&tempds; ods output Members=&tempds;
proc datasets library=WORK memtype=data; proc datasets library=WORK memtype=data;
%local wtcnt;%let wtcnt=0; %local wtcnt;%let wtcnt=0;
data _null_; set &tempds; data _null_;
if not (name =:"DATA"); set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1; i+1;
call symputx('wt'!!left(i),name); call symputx('wt'!!left(i),name);
call symputx('wtcnt',i); call symputx('wtcnt',i);

View File

@@ -1,18 +1,17 @@
/** /**
@file @file
@brief to be deprecated @brief Abort, ungracefully
@details We will deprecate this macro in 2022 @details Will abort with a straightforward %abort if the condition is true.
As you can see, it's not a macro function. <h4> Related Macros </h4>
@li mp_abort.sas
Use mp_abort.sas instead.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@cond @cond
**/ **/
%macro mf_abort(mac=mf_abort.sas, type=, msg=, iftrue=%str(1=1) %macro mf_abort(mac=mf_abort.sas, type=deprecated, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %if not(%eval(%unquote(&iftrue))) %then %return;
@@ -21,116 +20,8 @@
%if %length(&mac)>0 %then %put NOTE- called by &mac; %if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg; %put NOTE - &msg;
/* Stored Process Server web app context */ %abort;
%if %symexist(_metaperson) or "&SYSPROCESSNAME"="Compute Server" %then %do;
options obs=max replace nosyntaxcheck mprint;
/* extract log err / warn, if exist */
%local logloc logline;
%global logmsg; /* capture global messages */
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0;
data _null_;
infile &logloc lrecl=5000;
input; putlog _infile_;
i=1;
retain logonce 0;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0
then do;
call symputx('logline',_n_);
logonce+1;
end;
run;
/* capture log including lines BEFORE the err */
%if &logline>0 %then %do;
data _null_;
infile &logloc lrecl=5000;
input;
i=1;
stoploop=0;
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
input;
i+1;
stoploop=1;
end;
if stoploop=1 then stop;
run;
%end;
%end;
/* send response in SASjs JSON format */ %mend mf_abort;
data _null_;
file _webout mod lrecl=32000;
length msg $32767;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */
msg=compress(msg,,'kw');
/* quote without quoting the quotes (which are escaped instead) */
msg=cats('"',msg,'"');
if symexist('_debug') then debug=symget('_debug');
if debug ge 131 then put '>>weboutBEGIN<<';
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
put ',"sasjsAbort" : [{';
put ' "MSG":' msg ;
put ' ,"MAC": "' "&mac" '"}]';
put ",""SYSUSERID"" : ""&sysuserid"" ";
if symexist('_metauser') then do;
_METAUSER=quote(trim(symget('_METAUSER')));
put ",""_METAUSER"": " _METAUSER;
_METAPERSON=quote(trim(symget('_METAPERSON')));
put ',"_METAPERSON": ' _METAPERSON;
end;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
%if &_debug ge 131 %then %do;
put '>>weboutEND<<';
%end;
run;
%let syscc=0;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json";
%let rc=%sysfunc(fcopy(_web,_webout));
%end;
%else %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;
file skip;
put '%macro skip(); %macro skippy();';
run;
%inc skip;
%end;
%else %do;
%put _all_;
%abort cancel;
%end;
%mend;
/** @endcond */ /** @endcond */

View File

@@ -23,4 +23,4 @@
%if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0; %if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0;
%else 1; %else 1;
%mend; %mend mf_existds;

View File

@@ -66,7 +66,8 @@
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
%else %do; %else %do;
%put unable to open &libds (rc=&dsid); %put &sysmacroname: Unable to open &libds (rc=&dsid);
%put &sysmacroname: SYSMSG= %sysfunc(sysmsg());
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
&outvar &outvar

View File

@@ -102,7 +102,8 @@
%let fmtds=%scan(&syslast,2,.); %let fmtds=%scan(&syslast,2,.);
/* prepare formats and varnames */ /* prepare formats and varnames */
data _null_; data _null_;
set &fmtds end=last; if _n_=1 then call symputx('nobs',nobs,'l');
set &fmtds end=last nobs=nobs;
name=upcase(name); name=upcase(name);
/* fix formats */ /* fix formats */
if type=2 or type=6 then do; if type=2 or type=6 then do;
@@ -128,7 +129,6 @@
call symputx(cats('len',_n_),newlen,'l'); call symputx(cats('len',_n_),newlen,'l');
call symputx(cats('fmt',_n_),fmt,'l'); call symputx(cats('fmt',_n_),fmt,'l');
call symputx(cats('type',_n_),type,'l'); call symputx(cats('type',_n_),type,'l');
if last then call symputx('nobs',_n_,'l');
run; run;
data &fmtds; data &fmtds;
/* rename on entry */ /* rename on entry */

View File

@@ -42,6 +42,13 @@
*/ */
/*! \dir Tests
* \brief SASjs Tests
* \details These folders contain the macro tests. They are first compiled
and deployed (sasjs cbd) then executed (sasjs test).
*/
/*! \dir viya /*! \dir viya
* \brief Viya macros * \brief Viya macros
* \details These macros have the following attributes: * \details These macros have the following attributes:

View File

@@ -22,7 +22,7 @@ Usage:
%webout(OBJ,example2) * Object format, easier to work with ; %webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE) %webout(CLOSE)
;;;; ;;;;
%mm_createwebservice(path=/Public/app/common,name=appInit) %mm_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mm_createstp.sas @li mm_createstp.sas
@@ -37,12 +37,15 @@ Usage:
@param desc= The description of the service (optional) @param desc= The description of the service (optional)
@param precode= Space separated list of filerefs, pointing to the code that @param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the service (optional) needs to be attached to the beginning of the service (optional)
@param code= Space seperated fileref(s) of the actual code to be added @param code=(ft15f001) Space seperated fileref(s) of the actual code to be
@param server= The server which will run the STP. Server name or uri is fine. added
@param mDebug= set to 1 to show debug messages in the log @param server=(SASApp) The server which will run the STP. Server name or uri
@param replace= select YES to replace any existing service in that location is fine.
@param adapter= the macro uses the sasjs adapter by default. To use another @param mDebug=(0) set to 1 to show debug messages in the log
adapter, add a (different) fileref here. @param replace=(YES) select NO to avoid replacing an existing service in that
location
@param adapter=(sasjs) the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@@ -52,11 +55,11 @@ Usage:
%macro mm_createwebservice(path= %macro mm_createwebservice(path=
,name=initService ,name=initService
,precode= ,precode=
,code= ,code=ft15f001
,desc=This stp was created automagically by the mm_createwebservice macro ,desc=This stp was created automagically by the mm_createwebservice macro
,mDebug=0 ,mDebug=0
,server=SASApp ,server=SASApp
,replace=NO ,replace=YES
,adapter=sasjs ,adapter=sasjs
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -131,7 +134,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); '; put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ '; put ' /* prepare formats and varnames */ ';
put ' data _null_; '; put ' data _null_; ';
put ' set &fmtds end=last; '; put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); '; put ' name=upcase(name); ';
put ' /* fix formats */ '; put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; '; put ' if type=2 or type=6 then do; ';
@@ -157,7 +161,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; '; put ' run; ';
put ' data &fmtds; '; put ' data &fmtds; ';
put ' /* rename on entry */ '; put ' /* rename on entry */ ';
@@ -263,7 +266,12 @@ data _null_;
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); '; put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug '; put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; '; put ' sasjs_tables; ';
put '%local i tempds; '; put '%local i tempds jsonengine; ';
put ' ';
put '/* see https://github.com/sasjs/core/issues/41 */ ';
put '%if %upcase(&SYSENCODING)=WLATIN1 %then %let jsonengine=PROCJSON; ';
put '%else %let jsonengine=DATASTEP; ';
put ' ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
put ' %if %str(&_debug) ge 131 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
@@ -298,7 +306,7 @@ data _null_;
put ' OPTIONS NOBOMFILE; '; put ' OPTIONS NOBOMFILE; ';
put ' '; put ' ';
put ' /** '; put ' /** ';
put ' * check engine type to avoid the below err message: '; put ' * check xengine type to avoid the below err message: ';
put ' * > Function is only valid for filerefs using the CACHE access method. '; put ' * > Function is only valid for filerefs using the CACHE access method. ';
put ' */ '; put ' */ ';
put ' data _null_; '; put ' data _null_; ';
@@ -320,7 +328,7 @@ data _null_;
put ' '; put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,dbg=%str(&_debug) '; put ' ,engine=&jsonengine,dbg=%str(&_debug) ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -333,7 +341,7 @@ data _null_;
put ' %local wtcnt;%let wtcnt=0; '; put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; '; put ' data _null_; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if not (name =:"DATA"); '; put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
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''); ';
@@ -353,8 +361,8 @@ data _null_;
put ' put " ""&wt"" : {"; '; put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; '; put ' put ''"nlobs":'' nlobs; ';
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=&jsonengine) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) '; put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine) ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' %end; '; put ' %end; ';
@@ -468,4 +476,4 @@ run;
%put &url?_PROGRAM=&path/&name; %put &url?_PROGRAM=&path/&name;
%put ;%put ;%put ;%put ;%put ;%put ; %put ;%put ;%put ;%put ;%put ;%put ;
%mend; %mend mm_createwebservice;

View File

@@ -36,7 +36,12 @@
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
%local i tempds; %local i tempds jsonengine;
/* see https://github.com/sasjs/core/issues/41 */
%if %upcase(&SYSENCODING)=WLATIN1 %then %let jsonengine=PROCJSON;
%else %let jsonengine=DATASTEP;
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
%if %str(&_debug) ge 131 %then %do; %if %str(&_debug) ge 131 %then %do;
@@ -71,7 +76,7 @@
OPTIONS NOBOMFILE; OPTIONS NOBOMFILE;
/** /**
* check engine type to avoid the below err message: * check xengine type to avoid the below err message:
* > Function is only valid for filerefs using the CACHE access method. * > Function is only valid for filerefs using the CACHE access method.
*/ */
data _null_; data _null_;
@@ -93,7 +98,7 @@
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug) ,engine=&jsonengine,dbg=%str(&_debug)
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
@@ -106,7 +111,7 @@
%local wtcnt;%let wtcnt=0; %local wtcnt;%let wtcnt=0;
data _null_; data _null_;
set &tempds; set &tempds;
if not (name =:"DATA"); if not (upcase(name) =:"DATA"); /* ignore temp datasets */
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');
@@ -126,8 +131,8 @@
put " ""&wt"" : {"; put " ""&wt"" : {";
put '"nlobs":' nlobs; put '"nlobs":' nlobs;
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=&jsonengine)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine)
data _null_; file &fref mod encoding='utf-8'; data _null_; file &fref mod encoding='utf-8';
put "}"; put "}";
%end; %end;

View File

@@ -0,0 +1,34 @@
/**
@file
@brief Testing mfv_existfile macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfile.sas
@li mp_assert.sas
@li mv_createfile.sas
**/
options mprint sgen;
%let file=%mf_uid();
/* create a folder */
filename somefile temp;
data _null_;
file somefile;
put 'hello testings';
run;
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..txt,inref=somefile)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..txt)=1),
desc=Check if created file exists
)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/%mf_uid().txt)=0),
desc=Check if non created file does not exist
)

View File

@@ -0,0 +1,29 @@
/**
@file
@brief Testing mfv_existfolder macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfolder.sas
@li mp_assert.sas
@li mv_createfolder.sas
**/
options mprint sgen;
%let folder=%mf_uid();
/* create a folder */
%mv_createfolder(path=&mcTestAppLoc/temp/&folder)
%mp_assert(
iftrue=(%mfv_existfolder(&mcTestAppLoc/temp/&folder)=1),
desc=Check if created folder exists
)
%mp_assert(
iftrue=(%mfv_existfolder(&mcTestAppLoc/temp/&folder/%mf_uid()/noway)=0),
desc=Check if non created folder does not exist
)

View File

@@ -0,0 +1,42 @@
/**
@file
@brief Testing mv_createfile macro
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfile.sas
@li mp_assert.sas
@li mv_createfile.sas
**/
options mprint;
%let file=%mf_uid();
%put TEST 1 - basic file upload ;
filename somefile temp;
data _null_;
file somefile;
put 'hello testings';
run;
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..txt,inref=somefile)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..txt)=1),
desc=Check if created file exists
)
%put TEST 2 - dataset upload ;
data temp;
x=1;
run;
filename ds "%sysfunc(pathname(work))/temp.sas7bdat";
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..sas7bdat,inref=ds)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..sas7bdat)=1),
desc=Check if created dataset exists
)

View File

@@ -10,6 +10,8 @@
**/ **/
options mprint notes;
/** /**
* Test Case 1 * Test Case 1
*/ */

51
viya/mfv_existfile.sas Normal file
View File

@@ -0,0 +1,51 @@
/**
@file
@brief Checks whether a file exists in SAS Drive
@details Returns 1 if the file exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfile(/does/exist.txt);
%put %mfv_existfile(/does/not/exist.txt);
@param filepath The full path to the file on SAS drive (eg /Public/myfile.txt)
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfolder.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfile(filepath
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfile.sas with syscc=&syscc
)
%local fref rc path name;
%let fref=%mf_getuniquefileref();
%let name=%scan(&filepath,-1,/);
%let path=%substr(&filepath,1,%length(&filepath)-%length(&name)-1);
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path" filename="&name"))=0
%then %do;
%sysfunc(fexist(&fref))
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfile;

48
viya/mfv_existfolder.sas Normal file
View File

@@ -0,0 +1,48 @@
/**
@file
@brief Checks whether a folder exists in SAS Drive
@details Returns 1 if the folder exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfolder(/does/exist);
%put %mfv_existfolder(/does/not/exist);
@param path The path to the folder on SAS drive
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfile.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfolder(path
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfolder.sas with syscc=&syscc
)
%local fref rc;
%let fref=%mf_getuniquefileref();
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do;
1
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfolder;

113
viya/mv_createfile.sas Normal file
View File

@@ -0,0 +1,113 @@
/**
@file
@brief Creates a file in SAS Drive
@details Creates a file in SAS Drive and adds the appropriate content type.
If the parent folder does not exist, it is created.
Usage:
filename myfile temp;
data _null_;
file myfile;
put 'something';
run;
%mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile)
@param [in] path= The parent folder in which to create the file
@param [in] name= The name of the file to be created
@param [in] inref= The fileref pointing to the file to be uploaded
@param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline
@li attachment
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mv_createfolder.sas
**/
%macro mv_createfile(path=
,name=
,inref=
,contentdisp=inline
,access_token_var=ACCESS_TOKEN
,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;
%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)
)
%mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1)
,mac=&sysmacroname
,msg=%str(path value must be provided)
)
%mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1)
,mac=&sysmacroname
,msg=%str(name value with length >1 must be provided)
)
/* create folder if it does not already exist */
%mv_createfolder(path=&path
,access_token_var=&access_token_var
,grant_type=&grant_type
,mdebug=&mdebug
)
/* create file with relevant options */
%local fref;
%let fref=%mf_getuniquefileref();
filename &fref filesrvc
folderPath="&path"
filename="&name"
cdisp="&contentdisp";
%mp_binarycopy(inref=&inref, outref=&fref)
filename &fref clear;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%put &sysmacroname: File &name successfully created in &path;
%put &sysmacroname:;%put;
%put &base_uri/SASJobExecution?_file=&path/&name;%put;
%put &sysmacroname:;
%mend mv_createfile;

View File

@@ -1,17 +1,22 @@
/** /**
@file mv_createfolder.sas @file mv_createfolder.sas
@brief Creates a viya folder if that folder does not already exist @brief Creates a viya folder if that folder does not already exist
@details Expects oauth token in a global macro variable (default @details Creates a viya folder by checking if each parent folder exists, and
ACCESS_TOKEN). recursively creating children if needed.
Usage:
%mv_createfolder(path=/Public) %mv_createfolder(path=/Public)
@param path= The full path of the folder to be created @param [in] path= The full path of the folder to be created
@param 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
@param grant_type= (authorization_code) Valid values are "password" or token, if using authorization_code grant type.
"authorization_code" (unquoted). @param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@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
@@ -22,21 +27,36 @@
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas
@li mf_isblank.sas @li mf_isblank.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mfv_existfolder.sas
**/ **/
%macro mv_createfolder(path= %macro mv_createfolder(path=
,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=*;
%if %mfv_existfolder(&path)=1 %then %do;
%put &sysmacroname: &path already exists;
%return;
%end;
%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;
%else %let grant_type=sas_services; %else %let grant_type=sas_services;
%end; %end;
%if &grant_type=sas_services %then %do; %if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services; %let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=; %let &access_token_var=;
%end; %end;
%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
@@ -91,6 +111,15 @@ options noquotelenmax;
,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 &mdebug=1 %then %do;
%put &sysmacroname following check to see if &newpath exists:;
%put _local_;
data _null_;
set &fname1;
input;
putlog _infile_;
run;
%end;
%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_;
@@ -140,8 +169,10 @@ options noquotelenmax;
%put &sysmacroname &newpath now created. Grabbing the follow on link ; %put &sysmacroname &newpath now created. Grabbing the follow on link ;
data _null_; data _null_;
set &libref2..links; set &libref2..links;
if rel='createChild' then if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l'); call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=);
end;
run; run;
libname &libref2 clear; libname &libref2 clear;

View File

@@ -282,7 +282,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); '; put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ '; put ' /* prepare formats and varnames */ ';
put ' data _null_; '; put ' data _null_; ';
put ' set &fmtds end=last; '; put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); '; put ' name=upcase(name); ';
put ' /* fix formats */ '; put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; '; put ' if type=2 or type=6 then do; ';
@@ -308,7 +309,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; '; put ' run; ';
put ' data &fmtds; '; put ' data &fmtds; ';
put ' /* rename on entry */ '; put ' /* rename on entry */ ';
@@ -549,8 +549,9 @@ data _null_;
put ' ods output Members=&tempds; '; put ' ods output Members=&tempds; ';
put ' proc datasets library=WORK memtype=data; '; put ' proc datasets library=WORK memtype=data; ';
put ' %local wtcnt;%let wtcnt=0; '; put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; set &tempds; '; put ' data _null_; ';
put ' if not (name =:"DATA"); '; put ' set &tempds; ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; '; put ' i+1; ';
put ' call symputx(''wt''!!left(i),name); '; put ' call symputx(''wt''!!left(i),name); ';
put ' call symputx(''wtcnt'',i); '; put ' call symputx(''wtcnt'',i); ';

View File

@@ -174,8 +174,9 @@
ods output Members=&tempds; ods output Members=&tempds;
proc datasets library=WORK memtype=data; proc datasets library=WORK memtype=data;
%local wtcnt;%let wtcnt=0; %local wtcnt;%let wtcnt=0;
data _null_; set &tempds; data _null_;
if not (name =:"DATA"); set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1; i+1;
call symputx('wt'!!left(i),name); call symputx('wt'!!left(i),name);
call symputx('wtcnt',i); call symputx('wtcnt',i);