From 1cc92134675b548c40f641adca02b6a66df2ef9a Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:34:43 +0300 Subject: [PATCH 1/7] feat: refreshing mf_abort (it's now an actual macro function) --- base/mf_abort.sas | 123 +++------------------------------------------- 1 file changed, 7 insertions(+), 116 deletions(-) diff --git a/base/mf_abort.sas b/base/mf_abort.sas index 9bb28c3..91bffcd 100644 --- a/base/mf_abort.sas +++ b/base/mf_abort.sas @@ -1,18 +1,17 @@ /** @file - @brief to be deprecated - @details We will deprecate this macro in 2022 + @brief Abort, ungracefully + @details Will abort with a straightforward %abort if the condition is true. - As you can see, it's not a macro function. - - Use mp_abort.sas instead. +

Related Macros

+ @li mp_abort.sas @version 9.2 @author Allan Bowe @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*/; %if not(%eval(%unquote(&iftrue))) %then %return; @@ -21,116 +20,8 @@ %if %length(&mac)>0 %then %put NOTE- called by &mac; %put NOTE - &msg; - /* Stored Process Server web app context */ - %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; + %abort; - /* send response in SASjs JSON format */ - 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; +%mend mf_abort; /** @endcond */ \ No newline at end of file From ce331a23c8f2ec34dd30c1800ba1c7e02513a2dd Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:35:25 +0300 Subject: [PATCH 2/7] fix: ensuring obs is updated when the table has zero columns --- base/mp_jsonout.sas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/mp_jsonout.sas b/base/mp_jsonout.sas index 0fe4dc0..6b3a9f3 100644 --- a/base/mp_jsonout.sas +++ b/base/mp_jsonout.sas @@ -102,7 +102,8 @@ %let fmtds=%scan(&syslast,2,.); /* prepare formats and varnames */ data _null_; - set &fmtds end=last; + if _n_=1 then call symputx('nobs',nobs,'l'); + set &fmtds end=last nobs=nobs; name=upcase(name); /* fix formats */ if type=2 or type=6 then do; @@ -128,7 +129,6 @@ call symputx(cats('len',_n_),newlen,'l'); call symputx(cats('fmt',_n_),fmt,'l'); call symputx(cats('type',_n_),type,'l'); - if last then call symputx('nobs',_n_,'l'); run; data &fmtds; /* rename on entry */ From 8178b801fbb0262f8acad3f3cfb9af7388506c02 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:36:09 +0300 Subject: [PATCH 3/7] fix: using mfv_existfolder macro in mv_createfolder to save requests --- viya/mv_createfolder.sas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/viya/mv_createfolder.sas b/viya/mv_createfolder.sas index b6919ed..3ff7279 100644 --- a/viya/mv_createfolder.sas +++ b/viya/mv_createfolder.sas @@ -27,6 +27,8 @@ @li mf_getuniquelibref.sas @li mf_isblank.sas @li mf_getplatform.sas + @li mfv_existfolder.sas + **/ @@ -42,6 +44,11 @@ %end; %else %let dbg=*; +%if %mfv_existfolder(&path)=1 %then %do; + %put &sysmacroname: &path already exists; + %return; +%end; + %local oauth_bearer; %if &grant_type=detect %then %do; %if %symexist(&access_token_var) %then %let grant_type=authorization_code; From 42a16ef4963de41491b0195fdbc5be1dfe6472a1 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:36:43 +0300 Subject: [PATCH 4/7] feat: adding mfv_existfile.sas and tests --- tests/viya/mfv_existfile.test.sas | 34 ++++++++++++++++++++++ viya/mfv_existfile.sas | 48 +++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/viya/mfv_existfile.test.sas create mode 100644 viya/mfv_existfile.sas diff --git a/tests/viya/mfv_existfile.test.sas b/tests/viya/mfv_existfile.test.sas new file mode 100644 index 0000000..6207426 --- /dev/null +++ b/tests/viya/mfv_existfile.test.sas @@ -0,0 +1,34 @@ +/** + @file + @brief Testing mfv_existfile macro function + +

SAS Macros

+ @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 +) \ No newline at end of file diff --git a/viya/mfv_existfile.sas b/viya/mfv_existfile.sas new file mode 100644 index 0000000..51359ba --- /dev/null +++ b/viya/mfv_existfile.sas @@ -0,0 +1,48 @@ +/** + @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) + +

SAS Macros

+ @li mf_abort.sas + @li mf_getuniquefileref.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; \ No newline at end of file From 18bc6c889db1518671f3f19c98dd18ec4dabcd72 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:37:06 +0300 Subject: [PATCH 5/7] feat: adding mfv_existfolder.sas and tests --- tests/viya/mfv_existfolder.test.sas | 29 +++++++++++++++++++ viya/mfv_existfolder.sas | 45 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/viya/mfv_existfolder.test.sas create mode 100644 viya/mfv_existfolder.sas diff --git a/tests/viya/mfv_existfolder.test.sas b/tests/viya/mfv_existfolder.test.sas new file mode 100644 index 0000000..a676d86 --- /dev/null +++ b/tests/viya/mfv_existfolder.test.sas @@ -0,0 +1,29 @@ +/** + @file + @brief Testing mfv_existfolder macro function + +

SAS Macros

+ @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 +) \ No newline at end of file diff --git a/viya/mfv_existfolder.sas b/viya/mfv_existfolder.sas new file mode 100644 index 0000000..cdd3e9a --- /dev/null +++ b/viya/mfv_existfolder.sas @@ -0,0 +1,45 @@ +/** + @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 + +

SAS Macros

+ @li mf_abort.sas + @li mf_getuniquefileref.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; \ No newline at end of file From f9f43551439f53623341d72301a4f407ae42aef0 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:37:24 +0300 Subject: [PATCH 6/7] feat: adding mv_createfile.sas and tests --- tests/viya/mv_createfile.test.sas | 42 +++++++++++++ viya/mv_createfile.sas | 97 +++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 tests/viya/mv_createfile.test.sas create mode 100644 viya/mv_createfile.sas diff --git a/tests/viya/mv_createfile.test.sas b/tests/viya/mv_createfile.test.sas new file mode 100644 index 0000000..52ea2fc --- /dev/null +++ b/tests/viya/mv_createfile.test.sas @@ -0,0 +1,42 @@ +/** + @file + @brief Testing mv_createfile macro + +

SAS Macros

+ @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 +) \ No newline at end of file diff --git a/viya/mv_createfile.sas b/viya/mv_createfile.sas new file mode 100644 index 0000000..7382baf --- /dev/null +++ b/viya/mv_createfile.sas @@ -0,0 +1,97 @@ +/** + @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] 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 + +

SAS Macros

+ @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= + ,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"; + +%mp_binarycopy(inref=&inref, outref=&fref) + +filename &fref clear; + +%mend mv_createfile; \ No newline at end of file From d2764c3cd1a78e8f1df03bcf79cdc5e667092321 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 26 May 2021 23:37:38 +0300 Subject: [PATCH 7/7] chore: updating all.sas --- all.sas | 329 ++++++++++++++++++++++------------- meta/mm_createwebservice.sas | 4 +- viya/mv_createwebservice.sas | 4 +- 3 files changed, 211 insertions(+), 126 deletions(-) diff --git a/all.sas b/all.sas index 8a7bc9e..1dbe3d8 100644 --- a/all.sas +++ b/all.sas @@ -18,19 +18,18 @@ options noquotelenmax; /** @file - @brief to be deprecated - @details We will deprecate this macro in 2022 + @brief Abort, ungracefully + @details Will abort with a straightforward %abort if the condition is true. - As you can see, it's not a macro function. - - Use mp_abort.sas instead. +

Related Macros

+ @li mp_abort.sas @version 9.2 @author Allan Bowe @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*/; %if not(%eval(%unquote(&iftrue))) %then %return; @@ -39,117 +38,9 @@ options noquotelenmax; %if %length(&mac)>0 %then %put NOTE- called by &mac; %put NOTE - &msg; - /* Stored Process Server web app context */ - %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; + %abort; - /* send response in SASjs JSON format */ - 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; +%mend mf_abort; /** @endcond *//** @file mf_existds.sas @@ -5149,7 +5040,8 @@ create table &outds (rename=( %let fmtds=%scan(&syslast,2,.); /* prepare formats and varnames */ data _null_; - set &fmtds end=last; + if _n_=1 then call symputx('nobs',nobs,'l'); + set &fmtds end=last nobs=nobs; name=upcase(name); /* fix formats */ if type=2 or type=6 then do; @@ -5175,7 +5067,6 @@ create table &outds (rename=( call symputx(cats('len',_n_),newlen,'l'); call symputx(cats('fmt',_n_),fmt,'l'); call symputx(cats('type',_n_),type,'l'); - if last then call symputx('nobs',_n_,'l'); run; data &fmtds; /* rename on entry */ @@ -9013,7 +8904,8 @@ data _null_; put ' %let fmtds=%scan(&syslast,2,.); '; put ' /* prepare formats and varnames */ '; 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 ' /* fix formats */ '; put ' if type=2 or type=6 then do; '; @@ -9039,7 +8931,6 @@ data _null_; put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); '; - put ' if last then call symputx(''nobs'',_n_,''l''); '; put ' run; '; put ' data &fmtds; '; put ' /* rename on entry */ '; @@ -12890,6 +12781,193 @@ run; %inc &fref1; %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) + +

SAS Macros

+ @li mf_abort.sas + @li mf_getuniquefileref.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 + +

SAS Macros

+ @li mf_abort.sas + @li mf_getuniquefileref.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] 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 + +

SAS Macros

+ @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= + ,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"; + +%mp_binarycopy(inref=&inref, outref=&fref) + +filename &fref clear; + +%mend mv_createfile;/** @file mv_createfolder.sas @brief Creates a viya folder if that folder does not already exist @details Creates a viya folder by checking if each parent folder exists, and @@ -12918,6 +12996,8 @@ run; @li mf_getuniquelibref.sas @li mf_isblank.sas @li mf_getplatform.sas + @li mfv_existfolder.sas + **/ @@ -12933,6 +13013,11 @@ run; %end; %else %let dbg=*; +%if %mfv_existfolder(&path)=1 %then %do; + %put &sysmacroname: &path already exists; + %return; +%end; + %local oauth_bearer; %if &grant_type=detect %then %do; %if %symexist(&access_token_var) %then %let grant_type=authorization_code; @@ -13656,7 +13741,8 @@ data _null_; put ' %let fmtds=%scan(&syslast,2,.); '; put ' /* prepare formats and varnames */ '; 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 ' /* fix formats */ '; put ' if type=2 or type=6 then do; '; @@ -13682,7 +13768,6 @@ data _null_; put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); '; - put ' if last then call symputx(''nobs'',_n_,''l''); '; put ' run; '; put ' data &fmtds; '; put ' /* rename on entry */ '; diff --git a/meta/mm_createwebservice.sas b/meta/mm_createwebservice.sas index d4865fe..17f5f0e 100644 --- a/meta/mm_createwebservice.sas +++ b/meta/mm_createwebservice.sas @@ -134,7 +134,8 @@ data _null_; put ' %let fmtds=%scan(&syslast,2,.); '; put ' /* prepare formats and varnames */ '; 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 ' /* fix formats */ '; put ' if type=2 or type=6 then do; '; @@ -160,7 +161,6 @@ data _null_; put ' call symputx(cats(''len'',_n_),newlen,''l''); '; put ' call symputx(cats(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); '; - put ' if last then call symputx(''nobs'',_n_,''l''); '; put ' run; '; put ' data &fmtds; '; put ' /* rename on entry */ '; diff --git a/viya/mv_createwebservice.sas b/viya/mv_createwebservice.sas index 5e5bd40..f2a4616 100644 --- a/viya/mv_createwebservice.sas +++ b/viya/mv_createwebservice.sas @@ -282,7 +282,8 @@ data _null_; put ' %let fmtds=%scan(&syslast,2,.); '; put ' /* prepare formats and varnames */ '; 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 ' /* fix formats */ '; 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(''fmt'',_n_),fmt,''l''); '; put ' call symputx(cats(''type'',_n_),type,''l''); '; - put ' if last then call symputx(''nobs'',_n_,''l''); '; put ' run; '; put ' data &fmtds; '; put ' /* rename on entry */ ';