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

Compare commits

..

13 Commits

Author SHA1 Message Date
Allan Bowe
1096db0846 Merge pull request #229 from sasjs/runtimeissues
Improving WPS compatibility
2022-05-03 18:48:18 +03:00
Allan Bowe
fc9b765246 chore: updating all.sas 2022-05-03 15:46:34 +00:00
Allan Bowe
4a8f7bb014 fix: all the fixings 2022-05-03 15:46:15 +00:00
Allan Bowe
e0469be0d8 feat: updating mf_getvarcount to allow filtering by column type 2022-05-03 15:24:22 +00:00
Allan Bowe
e9e576b5ec fix: forcing misstype to NULL in ms_webout where not supported 2022-05-02 23:17:11 +00:00
Allan Bowe
1a32d114f1 fix: conditional execution of mp_init() 2022-05-02 22:32:32 +00:00
Allan Bowe
94e83f6b8d fix: updating mf_existfeature for constraint check 2022-05-02 22:24:56 +00:00
Allan Bowe
35a6dede6f fix: enabling ms_testservice() without inputs 2022-05-02 13:56:22 +00:00
Allan Bowe
039ec397dd chore: local scoping vars in mp_testservice 2022-04-30 19:16:25 +00:00
Allan Bowe
dce4630eb8 Merge pull request #228 from sasjs/allanbowe/add-markdown-as-mime-227
feat: adding MARKDOWN support to `mp_streamfile()`
2022-04-30 18:58:54 +03:00
Allan Bowe
1e142f042b chore: improving docs 2022-04-30 15:58:00 +00:00
Allan Bowe
7caca2f139 chore: typo in docs 2022-04-30 15:56:36 +00:00
Allan Bowe
61556b2de8 feat: adding MARKDOWN support to mp_streamfile(), correcting Content-type case issue also 2022-04-30 15:53:59 +00:00
14 changed files with 313 additions and 97 deletions

162
all.sas
View File

@@ -188,7 +188,7 @@ options noquotelenmax;
%put No feature was requested for detection; %put No feature was requested for detection;
%end; %end;
%else %if &feature=COLCONSTRAINTS %then %do; %else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0; %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 0;
%else 1; %else 1;
%end; %end;
%else %if &feature=PROCLUA %then %do; %else %if &feature=PROCLUA %then %do;
@@ -994,12 +994,12 @@ or %index(&pgm,/tests/testteardown)
@brief Returns an unused libref @brief Returns an unused libref
@details Use as follows: @details Use as follows:
libname mclib0 (work); libname mclib0 (work);
libname mclib1 (work); libname mclib1 (work);
libname mclib2 (work); libname mclib2 (work);
%let libref=%mf_getuniquelibref(); %let libref=%mf_getuniquelibref();
%put &=libref; %put &=libref;
which returns: which returns:
@@ -1148,33 +1148,50 @@ or %index(&pgm,/tests/testteardown)
@file @file
@brief Returns number of variables in a dataset @brief Returns number of variables in a dataset
@details Useful to identify those renagade datasets that have no columns! @details Useful to identify those renagade datasets that have no columns!
Can also be used to count for numeric, or character columns
%put Number of Variables=%mf_getvarcount(sashelp.class); %put Number of Variables=%mf_getvarcount(sashelp.class);
%put Character Variables=%mf_getvarcount(sashelp.class,typefilter=C);
%put Numeric Variables = %mf_getvarcount(sashelp.class,typefilter=N);
returns: returns:
> Number of Variables=4 > Number of Variables=4
@param libds Two part dataset (or view) reference.
@param [in] libds Two part dataset (or view) reference.
@param [in] typefilter= (A) Filter for certain types of column. Valid values:
@li A Count All columns
@li C Count Character columns only
@li N Count Numeric columns only
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getvarcount(libds %macro mf_getvarcount(libds,typefilter=A
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local dsid nvars rc ; %local dsid nvars rc outcnt x;
%let dsid=%sysfunc(open(&libds)); %let dsid=%sysfunc(open(&libds));
%let nvars=.; %let nvars=.;
%let outcnt=0;
%let typefilter=%upcase(&typefilter);
%if &dsid %then %do; %if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS)); %let nvars=%sysfunc(attrn(&dsid,NVARS));
%if &typefilter=A %then %let outcnt=&nvars;
%else %if &nvars>0 %then %do x=1 %to &nvars;
/* increment based on variable type */
%if %sysfunc(vartype(&dsid,&x))=&typefilter %then %do;
%let outcnt=%eval(&outcnt+1);
%end;
%end;
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
%else %do; %else %do;
%put unable to open &libds (rc=&dsid); %put unable to open &libds (rc=&dsid);
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
&nvars &outcnt
%mend mf_getvarcount;/** %mend mf_getvarcount;/**
@file @file
@brief Returns the format of a variable @brief Returns the format of a variable
@@ -2203,7 +2220,12 @@ Usage:
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
options obs=max replace nosyntaxcheck mprint; options obs=max replace mprint;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
%then %do;
options nosyntaxcheck;
%end;
%if &mode=INCLUDE %then %do; %if &mode=INCLUDE %then %do;
%if %sysfunc(exist(&errds))=1 %then %do; %if %sysfunc(exist(&errds))=1 %then %do;
data _null_; data _null_;
@@ -7458,6 +7480,7 @@ create table &outsummary as
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_length.sas @li mcf_length.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarcount.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mf_getvartype.sas
@li mf_getvarformat.sas @li mf_getvarformat.sas
@@ -7477,7 +7500,7 @@ create table &outsummary as
,outds=work.mp_getmaxvarlengths ,outds=work.mp_getmaxvarlengths
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local vars prefix x var fmt; %local vars prefix x var fmt srcds;
%let vars=%mf_getvarlist(libds=&libds); %let vars=%mf_getvarlist(libds=&libds);
%let prefix=%substr(%mf_getuniquename(),1,25); %let prefix=%substr(%mf_getuniquename(),1,25);
%let num2char=%upcase(&num2char); %let num2char=%upcase(&num2char);
@@ -7487,6 +7510,24 @@ create table &outsummary as
%mcf_length(wrap=YES, insert_cmplib=YES) %mcf_length(wrap=YES, insert_cmplib=YES)
%end; %end;
%if &num2char=NO
and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5")
and %mf_getvarcount(&libds,typefilter=N) gt 0
%then %do;
/* custom functions not supported in summary operations */
%let srcds=%mf_getuniquename();
data &srcds/view=&srcds;
set &libds;
%do x=1 %to %sysfunc(countw(&vars,%str( )));
%let var=%scan(&vars,&x);
%if %mf_getvartype(&libds,&var)=N %then %do;
&prefix.&x=mcf_length(&var);
%end;
%end;
run;
%end;
%else %let srcds=&libds;
proc sql; proc sql;
create table &outds (rename=( create table &outds (rename=(
%do x=1 %to %sysfunc(countw(&vars,%str( ))); %do x=1 %to %sysfunc(countw(&vars,%str( )));
@@ -7511,10 +7552,15 @@ create table &outds (rename=(
%end; %end;
%end; %end;
%else %do; %else %do;
max(mcf_length(&var)) as &prefix.&x %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
max(&prefix.&x) as &prefix.&x
%end;
%else %do;
max(mcf_length(&var)) as &prefix.&x
%end;
%end; %end;
%end; %end;
from &libds; from &srcds;
proc transpose data=&outds proc transpose data=&outds
out=&outds(rename=(_name_=NAME COL1=MAXLEN)); out=&outds(rename=(_name_=NAME COL1=MAXLEN));
@@ -8443,7 +8489,7 @@ options
validvarname=V7 /* avoid special characters etc in variable names */ validvarname=V7 /* avoid special characters etc in variable names */
varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */ varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */
varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */ varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */
%if %substr(&sysver,1,1) ne 4 %then %do; %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
noautocorrect /* disallow misspelled procedure names */ noautocorrect /* disallow misspelled procedure names */
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */ dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
%end; %end;
@@ -11546,7 +11592,7 @@ select distinct tgtvar_nm into: missvars separated by ' '
data &ds1; data &ds1;
set &dslist indsname=&inds_auto; set &dslist indsname=&inds_auto;
&hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.); &hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.);
&inds_keep=&inds_auto; &inds_keep=upcase(&inds_auto);
proc sort; proc sort;
by &inds_keep &hashkey; by &inds_keep &hashkey;
run; run;
@@ -11581,8 +11627,8 @@ data &ds4;
tgtvar_nm=upcase(tgtvar_nm); tgtvar_nm=upcase(tgtvar_nm);
if tgtvar_nm in (%upcase(&vlist)); if tgtvar_nm in (%upcase(&vlist));
if &inds_auto="&ds2" then tgtvar_type='N'; if upcase(&inds_auto)="&ds2" then tgtvar_type='N';
else if &inds_auto="&ds3" then tgtvar_type='C'; else if upcase(&inds_auto)="&ds3" then tgtvar_type='C';
else do; else do;
putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto; putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto;
call symputx('syscc',98); call symputx('syscc',98);
@@ -11722,8 +11768,9 @@ create table &outds as
%mend mp_stprequests;/** %mend mp_stprequests;/**
@file @file
@brief Streams a file to _webout according to content type @brief Streams a file to _webout according to content type
@details Will set headers using appropriate functions (SAS 9 vs Viya) and send @details Will set headers using appropriate functions per the server type
content as a binary stream. (Viya, EBI, [SASjs Server](https://github.com/sasjs/server)) and stream
content using mp_binarycopy().
Usage: Usage:
@@ -11733,7 +11780,14 @@ create table &outds as
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXT) Either TEXT, ZIP, CSV, EXCEL @param [in] contenttype= (TEXT) Supported:
@li CSV
@li EXCEL
@li MARKDOWN
@li TEXT
@li ZIP
Feel free to submit PRs to support more mime types! The official list is
here: https://www.iana.org/assignments/media-types/media-types.xhtml
@param [in] inloc= /path/to/file.ext to be sent @param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`) @param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute. @param [in] iftrue= (1=1) Provide a condition under which to execute.
@@ -11779,7 +11833,7 @@ run;
%if &contentype=CSV %then %do; %if &contentype=CSV %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -11789,7 +11843,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/csv) %mfs_httpheader(Content-Type,application/csv)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
@@ -11797,7 +11851,7 @@ run;
/* suitable for XLS format */ /* suitable for XLS format */
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -11807,14 +11861,14 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/vnd.ms-excel) %mfs_httpheader(Content-Type,application/vnd.ms-excel)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do; %else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type',"image/%lowcase(&contenttype)"); rc=stpsrv_header('Content-Type',"image/%lowcase(&contenttype)");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
@@ -11822,30 +11876,30 @@ run;
contenttype="image/%lowcase(&contenttype)"; contenttype="image/%lowcase(&contenttype)";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,image/%lowcase(&contenttype)) %mfs_httpheader(Content-Type,image/%lowcase(&contenttype))
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do; %else %if &contentype=HTML or &contenttype=MARKDOWN %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','text/html'); rc=stpsrv_header('Content-Type',"text/%lowcase(&contenttype)");
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json" filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html" contenttype="text/%lowcase(&contenttype)"
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,text/html) %mfs_httpheader(Content-Type,text/%lowcase(&contenttype))
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=TEXT %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -11855,14 +11909,14 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/text) %mfs_httpheader(Content-Type,application/text)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do; %else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)"); rc=stpsrv_header('Content-Type',"font/%lowcase(&contenttype)");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
@@ -11870,13 +11924,13 @@ run;
contenttype="font/%lowcase(&contenttype)"; contenttype="font/%lowcase(&contenttype)";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,font/%lowcase(&contenttype)) %mfs_httpheader(Content-Type,font/%lowcase(&contenttype))
%end; %end;
%end; %end;
%else %if &contentype=XLSX %then %do; %else %if &contentype=XLSX %then %do;
%if (&platform=SASMETA and &streamweb=1) %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');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
@@ -11888,7 +11942,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type %mfs_httpheader(Content-Type
,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet ,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
) )
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
@@ -11897,7 +11951,7 @@ run;
%else %if &contentype=ZIP %then %do; %else %if &contentype=ZIP %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -11907,7 +11961,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/zip) %mfs_httpheader(Content-Type,application/zip)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
@@ -19799,6 +19853,11 @@ 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 "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do; ';
put ' /* functions in formats unsupported */ ';
put ' %put &sysmacroname: forcing missing back to NULL as feature not supported; ';
put ' %let missing=NULL; ';
put ' %end; ';
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,missing=&missing,showmeta=&showmeta '; put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
put ' ) '; put ' ) ';
@@ -20401,7 +20460,7 @@ options &optval;
outref=0, outref=0,
outlogds=_null_ outlogds=_null_
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local dbg fref1 chopout1 chopout2; %local dbg i var ds1 fref1 chopout1 chopout2;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
@@ -20424,13 +20483,15 @@ options &optval;
%let ds1=%mf_getuniquename(); %let ds1=%mf_getuniquename();
data &ds1; data &ds1;
length fileref $8 name $32 filename $256 var $300; length fileref $8 name $32 filename $256 var $300;
webcount=countw("&inputfiles"); if "&inputfiles" ne "0" then do;
do i=1 to webcount; webcount=countw("&inputfiles");
var=scan("&inputfiles",i,' '); do i=1 to webcount;
fileref=scan(var,1,':'); var=scan("&inputfiles",i,' ');
name=scan(var,2,':'); fileref=scan(var,1,':');
filename=cats(name,'.csv'); name=scan(var,2,':');
output; filename=cats(name,'.csv');
output;
end;
end; end;
run; run;
@@ -20593,6 +20654,11 @@ run;
%end; %end;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
/* functions in formats unsupported */
%put &sysmacroname: forcing missing back to NULL as feature not supported;
%let missing=NULL;
%end;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,missing=&missing,showmeta=&showmeta ,engine=DATASTEP,missing=&missing,showmeta=&showmeta
) )

View File

@@ -30,7 +30,7 @@
%put No feature was requested for detection; %put No feature was requested for detection;
%end; %end;
%else %if &feature=COLCONSTRAINTS %then %do; %else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0; %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 0;
%else 1; %else 1;
%end; %end;
%else %if &feature=PROCLUA %then %do; %else %if &feature=PROCLUA %then %do;

View File

@@ -3,12 +3,12 @@
@brief Returns an unused libref @brief Returns an unused libref
@details Use as follows: @details Use as follows:
libname mclib0 (work); libname mclib0 (work);
libname mclib1 (work); libname mclib1 (work);
libname mclib2 (work); libname mclib2 (work);
%let libref=%mf_getuniquelibref(); %let libref=%mf_getuniquelibref();
%put &=libref; %put &=libref;
which returns: which returns:

View File

@@ -2,31 +2,48 @@
@file @file
@brief Returns number of variables in a dataset @brief Returns number of variables in a dataset
@details Useful to identify those renagade datasets that have no columns! @details Useful to identify those renagade datasets that have no columns!
Can also be used to count for numeric, or character columns
%put Number of Variables=%mf_getvarcount(sashelp.class); %put Number of Variables=%mf_getvarcount(sashelp.class);
%put Character Variables=%mf_getvarcount(sashelp.class,typefilter=C);
%put Numeric Variables = %mf_getvarcount(sashelp.class,typefilter=N);
returns: returns:
> Number of Variables=4 > Number of Variables=4
@param libds Two part dataset (or view) reference.
@param [in] libds Two part dataset (or view) reference.
@param [in] typefilter= (A) Filter for certain types of column. Valid values:
@li A Count All columns
@li C Count Character columns only
@li N Count Numeric columns only
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getvarcount(libds %macro mf_getvarcount(libds,typefilter=A
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local dsid nvars rc ; %local dsid nvars rc outcnt x;
%let dsid=%sysfunc(open(&libds)); %let dsid=%sysfunc(open(&libds));
%let nvars=.; %let nvars=.;
%let outcnt=0;
%let typefilter=%upcase(&typefilter);
%if &dsid %then %do; %if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS)); %let nvars=%sysfunc(attrn(&dsid,NVARS));
%if &typefilter=A %then %let outcnt=&nvars;
%else %if &nvars>0 %then %do x=1 %to &nvars;
/* increment based on variable type */
%if %sysfunc(vartype(&dsid,&x))=&typefilter %then %do;
%let outcnt=%eval(&outcnt+1);
%end;
%end;
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
%else %do; %else %do;
%put unable to open &libds (rc=&dsid); %put unable to open &libds (rc=&dsid);
%let rc=%sysfunc(close(&dsid)); %let rc=%sysfunc(close(&dsid));
%end; %end;
&nvars &outcnt
%mend mf_getvarcount; %mend mf_getvarcount;

View File

@@ -89,7 +89,12 @@
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
options obs=max replace nosyntaxcheck mprint; options obs=max replace mprint;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
%then %do;
options nosyntaxcheck;
%end;
%if &mode=INCLUDE %then %do; %if &mode=INCLUDE %then %do;
%if %sysfunc(exist(&errds))=1 %then %do; %if %sysfunc(exist(&errds))=1 %then %do;
data _null_; data _null_;

View File

@@ -41,6 +41,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mcf_length.sas @li mcf_length.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarcount.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mf_getvartype.sas
@li mf_getvarformat.sas @li mf_getvarformat.sas
@@ -60,7 +61,7 @@
,outds=work.mp_getmaxvarlengths ,outds=work.mp_getmaxvarlengths
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local vars prefix x var fmt; %local vars prefix x var fmt srcds;
%let vars=%mf_getvarlist(libds=&libds); %let vars=%mf_getvarlist(libds=&libds);
%let prefix=%substr(%mf_getuniquename(),1,25); %let prefix=%substr(%mf_getuniquename(),1,25);
%let num2char=%upcase(&num2char); %let num2char=%upcase(&num2char);
@@ -70,6 +71,24 @@
%mcf_length(wrap=YES, insert_cmplib=YES) %mcf_length(wrap=YES, insert_cmplib=YES)
%end; %end;
%if &num2char=NO
and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5")
and %mf_getvarcount(&libds,typefilter=N) gt 0
%then %do;
/* custom functions not supported in summary operations */
%let srcds=%mf_getuniquename();
data &srcds/view=&srcds;
set &libds;
%do x=1 %to %sysfunc(countw(&vars,%str( )));
%let var=%scan(&vars,&x);
%if %mf_getvartype(&libds,&var)=N %then %do;
&prefix.&x=mcf_length(&var);
%end;
%end;
run;
%end;
%else %let srcds=&libds;
proc sql; proc sql;
create table &outds (rename=( create table &outds (rename=(
%do x=1 %to %sysfunc(countw(&vars,%str( ))); %do x=1 %to %sysfunc(countw(&vars,%str( )));
@@ -94,10 +113,15 @@ create table &outds (rename=(
%end; %end;
%end; %end;
%else %do; %else %do;
max(mcf_length(&var)) as &prefix.&x %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
max(&prefix.&x) as &prefix.&x
%end;
%else %do;
max(mcf_length(&var)) as &prefix.&x
%end;
%end; %end;
%end; %end;
from &libds; from &srcds;
proc transpose data=&outds proc transpose data=&outds
out=&outds(rename=(_name_=NAME COL1=MAXLEN)); out=&outds(rename=(_name_=NAME COL1=MAXLEN));

View File

@@ -67,7 +67,7 @@ options
validvarname=V7 /* avoid special characters etc in variable names */ validvarname=V7 /* avoid special characters etc in variable names */
varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */ varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */
varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */ varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */
%if %substr(&sysver,1,1) ne 4 %then %do; %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
noautocorrect /* disallow misspelled procedure names */ noautocorrect /* disallow misspelled procedure names */
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */ dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
%end; %end;

View File

@@ -125,7 +125,7 @@
data &ds1; data &ds1;
set &dslist indsname=&inds_auto; set &dslist indsname=&inds_auto;
&hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.); &hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.);
&inds_keep=&inds_auto; &inds_keep=upcase(&inds_auto);
proc sort; proc sort;
by &inds_keep &hashkey; by &inds_keep &hashkey;
run; run;
@@ -160,8 +160,8 @@ data &ds4;
tgtvar_nm=upcase(tgtvar_nm); tgtvar_nm=upcase(tgtvar_nm);
if tgtvar_nm in (%upcase(&vlist)); if tgtvar_nm in (%upcase(&vlist));
if &inds_auto="&ds2" then tgtvar_type='N'; if upcase(&inds_auto)="&ds2" then tgtvar_type='N';
else if &inds_auto="&ds3" then tgtvar_type='C'; else if upcase(&inds_auto)="&ds3" then tgtvar_type='C';
else do; else do;
putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto; putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto;
call symputx('syscc',98); call symputx('syscc',98);

View File

@@ -1,8 +1,9 @@
/** /**
@file @file
@brief Streams a file to _webout according to content type @brief Streams a file to _webout according to content type
@details Will set headers using appropriate functions (SAS 9 vs Viya) and send @details Will set headers using appropriate functions per the server type
content as a binary stream. (Viya, EBI, [SASjs Server](https://github.com/sasjs/server)) and stream
content using mp_binarycopy().
Usage: Usage:
@@ -12,7 +13,14 @@
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXT) Either TEXT, ZIP, CSV, EXCEL @param [in] contenttype= (TEXT) Supported:
@li CSV
@li EXCEL
@li MARKDOWN
@li TEXT
@li ZIP
Feel free to submit PRs to support more mime types! The official list is
here: https://www.iana.org/assignments/media-types/media-types.xhtml
@param [in] inloc= /path/to/file.ext to be sent @param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`) @param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute. @param [in] iftrue= (1=1) Provide a condition under which to execute.
@@ -58,7 +66,7 @@ run;
%if &contentype=CSV %then %do; %if &contentype=CSV %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -68,7 +76,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/csv) %mfs_httpheader(Content-Type,application/csv)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
@@ -76,7 +84,7 @@ run;
/* suitable for XLS format */ /* suitable for XLS format */
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -86,14 +94,14 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/vnd.ms-excel) %mfs_httpheader(Content-Type,application/vnd.ms-excel)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do; %else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type',"image/%lowcase(&contenttype)"); rc=stpsrv_header('Content-Type',"image/%lowcase(&contenttype)");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
@@ -101,30 +109,30 @@ run;
contenttype="image/%lowcase(&contenttype)"; contenttype="image/%lowcase(&contenttype)";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,image/%lowcase(&contenttype)) %mfs_httpheader(Content-Type,image/%lowcase(&contenttype))
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do; %else %if &contentype=HTML or &contenttype=MARKDOWN %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type','text/html'); rc=stpsrv_header('Content-Type',"text/%lowcase(&contenttype)");
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json" filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
contenttype="text/html" contenttype="text/%lowcase(&contenttype)"
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,text/html) %mfs_httpheader(Content-Type,text/%lowcase(&contenttype))
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=TEXT %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -134,14 +142,14 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/text) %mfs_httpheader(Content-Type,application/text)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do; %else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
%if (&platform=SASMETA and &streamweb=1) %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_; data _null_;
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)"); rc=stpsrv_header('Content-Type',"font/%lowcase(&contenttype)");
run; run;
%end; %end;
%else %if &platform=SASVIYA %then %do; %else %if &platform=SASVIYA %then %do;
@@ -149,13 +157,13 @@ run;
contenttype="font/%lowcase(&contenttype)"; contenttype="font/%lowcase(&contenttype)";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,font/%lowcase(&contenttype)) %mfs_httpheader(Content-Type,font/%lowcase(&contenttype))
%end; %end;
%end; %end;
%else %if &contentype=XLSX %then %do; %else %if &contentype=XLSX %then %do;
%if (&platform=SASMETA and &streamweb=1) %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');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname"); rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run; run;
@@ -167,7 +175,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type %mfs_httpheader(Content-Type
,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet ,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
) )
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
@@ -176,7 +184,7 @@ run;
%else %if &contentype=ZIP %then %do; %else %if &contentype=ZIP %then %do;
%if (&platform=SASMETA and &streamweb=1) %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");
run; run;
%end; %end;
@@ -186,7 +194,7 @@ run;
contentdisp="attachment; filename=&outname"; contentdisp="attachment; filename=&outname";
%end; %end;
%else %if &platform=SASJS %then %do; %else %if &platform=SASJS %then %do;
%mfs_httpheader(Content-type,application/zip) %mfs_httpheader(Content-Type,application/zip)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname)) %mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;

View File

@@ -390,6 +390,11 @@ 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 "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do; ';
put ' /* functions in formats unsupported */ ';
put ' %put &sysmacroname: forcing missing back to NULL as feature not supported; ';
put ' %let missing=NULL; ';
put ' %end; ';
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,missing=&missing,showmeta=&showmeta '; put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
put ' ) '; put ' ) ';

View File

@@ -59,7 +59,7 @@
outref=0, outref=0,
outlogds=_null_ outlogds=_null_
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local dbg fref1 chopout1 chopout2; %local dbg i var ds1 fref1 chopout1 chopout2;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
@@ -82,13 +82,15 @@
%let ds1=%mf_getuniquename(); %let ds1=%mf_getuniquename();
data &ds1; data &ds1;
length fileref $8 name $32 filename $256 var $300; length fileref $8 name $32 filename $256 var $300;
webcount=countw("&inputfiles"); if "&inputfiles" ne "0" then do;
do i=1 to webcount; webcount=countw("&inputfiles");
var=scan("&inputfiles",i,' '); do i=1 to webcount;
fileref=scan(var,1,':'); var=scan("&inputfiles",i,' ');
name=scan(var,2,':'); fileref=scan(var,1,':');
filename=cats(name,'.csv'); name=scan(var,2,':');
output; filename=cats(name,'.csv');
output;
end;
end; end;
run; run;

View File

@@ -100,6 +100,11 @@
%end; %end;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
/* functions in formats unsupported */
%put &sysmacroname: forcing missing back to NULL as feature not supported;
%let missing=NULL;
%end;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,missing=&missing,showmeta=&showmeta ,engine=DATASTEP,missing=&missing,showmeta=&showmeta
) )

View File

@@ -0,0 +1,46 @@
/**
@file
@brief Testing mf_getvarlist macro
<h4> SAS Macros </h4>
@li mf_getvarcount.sas
@li mp_assertscope.sas
**/
data work.all work.nums(keep=num1 num2) work.chars(keep=char1 char2);
length num1 num2 8 char1 char2 char3 $4;
call missing (of _all_);
output;
run;
%mp_assertscope(SNAPSHOT)
%put scope check:%mf_getvarcount(work.all);
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(%mf_getvarcount(work.all)=5),
desc=%str(Checking for mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.all,typefilter=C)=3),
desc=%str(Checking for char in mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.all,typefilter=N)=2),
desc=%str(Checking for num in mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.nums,typefilter=c)=0),
desc=%str(Checking for char in num vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.chars,typefilter=N)=0),
desc=%str(Checking for num in char vars),
outds=work.test_results
)

View File

@@ -10,10 +10,48 @@
**/ **/
data work.class ;
attrib
Name length= $8
Sex length= $1
Age length= 8
Height length= 8
Weight length= 8
;
infile cards dsd;
input
Name :$char.
Sex :$char.
Age
Height
Weight
;
datalines4;
Alfred,M,14,69,112.5
Alice,F,13,56.5,84
Barbara,F,13,65.3,98
Carol,F,14,62.8,102.5
Henry,M,14,63.5,102.5
James,M,12,57.3,83
Jane,F,12,59.8,84.5
Janet,F,15,62.5,112.5
Jeffrey,M,13,62.5,84
John,M,12,59,99.5
Joyce,F,11,51.3,50.5
Judy,F,14,64.3,90
Louise,F,12,56.3,77
Mary,F,15,66.5,112
Philip,M,16,72,150
Robert,M,12,64.8,128
Ronald,M,15,67,133
Thomas,M,11,57.5,85
William,M,15,66.5,112
;;;;
run;
/* regular usage */ /* regular usage */
%mp_assertscope(SNAPSHOT) %mp_assertscope(SNAPSHOT)
%mp_getmaxvarlengths(sashelp.class,outds=work.myds) %mp_getmaxvarlengths(work.class,outds=work.myds)
%mp_assertscope(COMPARE,desc=checking scope leakage on mp_getmaxvarlengths) %mp_assertscope(COMPARE,desc=checking scope leakage on mp_getmaxvarlengths)
%mp_assert( %mp_assert(
iftrue=(&syscc=0), iftrue=(&syscc=0),