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

Compare commits

..

28 Commits

Author SHA1 Message Date
Allan Bowe
6938a42896 Merge pull request #215 from sasjs/serverconfig
Change test server & update mx_webout() macros
2022-04-14 15:41:44 +03:00
munja
efff77c94e fix: mx_webout 2022-04-14 13:40:14 +01:00
Allan Bowe
134b91f266 fix: avoiding running tests on viya 2022-04-14 11:14:35 +00:00
Allan Bowe
969f551e10 Merge pull request #214 from sasjs/cond
fix: adding cond/endcond to mp_ds2cards
2022-04-13 23:34:52 +03:00
munja
26623ba085 fix: adding cond/endcond to mp_ds2cards 2022-04-13 21:32:47 +01:00
Allan Bowe
8eb495890d Merge pull request #213 from sasjs/issue212
fix: ensuring indexes are picked up in mp_getpk().  Closes #212
2022-04-13 15:59:22 +03:00
munja
c1a30977f1 chore: removing serverurl 2022-04-13 13:58:55 +01:00
munja
9a6be61651 fix: ensuring indexes are picked up in mp_getpk(). Closes #212 2022-04-13 13:57:43 +01:00
Allan Bowe
388839039e Merge pull request #211 from sasjs/streamhtmlasfile
fix: send html as attachment rather than streamed content
2022-04-11 12:56:02 +03:00
Allan Bowe
e760a89a6a fix: send html as attachment rather than streamed content when mp_streamfile is used on all platforms 2022-04-11 09:54:07 +00:00
Allan Bowe
d2e30267e8 Merge pull request #210 from sasjs/nulfixes
fix: using regex special chars instead of hex constants in mp_jsonout
2022-04-07 11:53:37 +03:00
munja
190dbddfe3 fix: using regex special chars instead of hex constants in mp_jsonout 2022-04-07 09:52:56 +01:00
Allan Bowe
05e769794e Merge pull request #209 from sasjs/missref
fix: avoid: ERROR: Variable "fref" may not be initialized
2022-04-06 18:26:45 +03:00
munja
558ebaf6f2 fix: avoid: ERROR: Variable "fref" may not be initialized 2022-04-06 16:25:50 +01:00
Allan Bowe
970b56fe5a Merge pull request #208 from sasjs/issue207
fix: removing LUA dependency from mv_webout to enable Viya 4 compatibility
2022-04-01 20:42:22 +03:00
munja
c2597bd07b fix: missing dependency in mp_hashdataset.test.sas 2022-04-01 17:29:06 +01:00
munja
c4baca477b fix: removing LUA dependency from mv_webout to enable Viya 4 compatibility 2022-04-01 16:56:49 +01:00
Allan Bowe
7726b0e0b0 Merge pull request #206 from sasjs/ms_getfile
fix: ensuring ms_getfile works on specific installs
2022-03-29 20:41:20 +03:00
munja
0a536245f3 fix: missing dependency in mp_hashdataset.test.sas 2022-03-29 18:40:58 +01:00
munja
edfa9ecc07 fix: ensuring ms_getfile works on specific installs 2022-03-29 18:08:24 +01:00
munja
f4982c85ca fix: adding nonote2err option on mp_hashdataset 2022-03-29 15:00:33 +01:00
Allan Bowe
3ce771d587 Merge pull request #205 from sasjs/issue204
fix: updating mp_hashdataset to cope with STRICT mode.  Adding test a…
2022-03-29 15:47:17 +03:00
munja
72d6b446c3 fix: updating mp_hashdataset to cope with STRICT mode. Adding test and improving sasjs/server compatibility. 2022-03-29 13:22:24 +01:00
Allan Bowe
40d694eec8 Merge pull request #203 from sasjs/invisibles
fix: support SOH, STX and DC1 control characters in mp_jsonout
2022-03-29 12:02:09 +03:00
munja
6af1423666 fix: more invisibles 2022-03-28 16:26:58 +01:00
munja
23a01347f1 fix: support SOH, STX and DC1 control characters in mp_jsonout 2022-03-28 15:54:28 +01:00
Allan Bowe
7c86d6163a Merge pull request #201 from sasjs/mm_assignlib_fix
fix: enabling more descriptive mm_assignlib abort messages when library cannot be assigned
2022-03-21 18:10:56 +02:00
munja
d7233208f1 fix: enabling more descriptive mm_assignlib abort messages when library cannot be assigned 2022-03-21 16:07:27 +00:00
22 changed files with 934 additions and 2492 deletions

405
all.sas
View File

@@ -2194,7 +2194,7 @@ Usage:
%end; %end;
/* Stored Process Server web app context */ /* Stored Process Server web app context */
%if %symexist(_metaport) %if %symexist(_METAFOLDER)
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
@@ -2270,12 +2270,14 @@ Usage:
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
data _null_; data _null_;
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg syswarningtext syserrortext $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=symget('msg'); msg=symget('msg');
%if &logline>0 %then %do; %if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg')); msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end; %end;
/* escape the escapes */
msg=tranwrd(msg,'\','\\');
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */
@@ -3200,7 +3202,7 @@ run;
proc compare proc compare
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist)))) base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds; compare=&ds noprint;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;
@@ -4306,6 +4308,7 @@ run;
data &out_ds; data &out_ds;
set &out_ds; set &out_ds;
length infoname infoval $60 fref $8; length infoname infoval $60 fref $8;
if _n_=1 then call missing(fref);
rc=filename(fref,filepath); rc=filename(fref,filepath);
drop rc infoname fid i close fref; drop rc infoname fid i close fref;
if file_or_folder='file' then do; if file_or_folder='file' then do;
@@ -4542,6 +4545,7 @@ drop table &out_ds;
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@cond
**/ **/
%macro mp_ds2cards(base_ds=, tgt_ds= %macro mp_ds2cards(base_ds=, tgt_ds=
@@ -4713,7 +4717,8 @@ data _null_;
put ' @file'; put ' @file';
put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset"; put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset";
put " @details Generated by %nrstr(%%)mp_ds2cards()"; put " @details Generated by %nrstr(%%)mp_ds2cards()";
put " Available on github.com/sasjs/core"; put " Source: https://github.com/sasjs/core";
put ' @cond ';
put '**/'; put '**/';
put "data &tgt_ds &indexes;"; put "data &tgt_ds &indexes;";
put "attrib "; put "attrib ";
@@ -4758,6 +4763,7 @@ data _null_;
if __lastobs then do; if __lastobs then do;
put ';;;;'; put ';;;;';
put 'run;'; put 'run;';
put '/** @endcond **/';
stop; stop;
end; end;
run; run;
@@ -4777,7 +4783,9 @@ quit;
%put NOTE-;%put NOTE-; %put NOTE-;%put NOTE-;
%put NOTE- %sysfunc(dequote(&cards_file.)); %put NOTE- %sysfunc(dequote(&cards_file.));
%put NOTE-;%put NOTE-; %put NOTE-;%put NOTE-;
%mend mp_ds2cards;/** %mend mp_ds2cards;
/** @endcond **/
/**
@file @file
@brief Export a dataset to a CSV file WITH leading blanks @brief Export a dataset to a CSV file WITH leading blanks
@details Export a dataset to a file or fileref, retaining leading blanks. @details Export a dataset to a file or fileref, retaining leading blanks.
@@ -7359,7 +7367,8 @@ create table &outds (rename=(
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks; %local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks
pkfromindex;
%let lib=%upcase(&lib); %let lib=%upcase(&lib);
%let ds=%upcase(&ds); %let ds=%upcase(&ds);
@@ -7374,6 +7383,7 @@ create table &outds (rename=(
%let sum=%mf_getuniquename(prefix=getpk_sum); %let sum=%mf_getuniquename(prefix=getpk_sum);
%let pk4sure=%mf_getuniquename(prefix=getpk_pk4sure); %let pk4sure=%mf_getuniquename(prefix=getpk_pk4sure);
%let pkdefault=%mf_getuniquename(prefix=getpk_pkdefault); %let pkdefault=%mf_getuniquename(prefix=getpk_pkdefault);
%let pkfromindex=%mf_getuniquename(prefix=getpk_pkfromindex);
%let finalpks=%mf_getuniquename(prefix=getpk_finalpks); %let finalpks=%mf_getuniquename(prefix=getpk_finalpks);
%local dbg; %local dbg;
@@ -7484,9 +7494,23 @@ create table &ds1 as
and a.constraint_name=b.constraint_name and a.constraint_name=b.constraint_name
order by 1,2,3,4; order by 1,2,3,4;
/* extract cols from the relevant unique INDEXES */
create table &pkfromindex as
select libname as libref
,memname as table_name
,indxname as constraint_name
,indxpos as constraint_order
,name
from dictionary.indexes
where nomiss='yes' and unique='yes' and upcase(libname)="&lib"
%if &ds ne 0 %then %do;
and upcase(memname)="&ds"
%end;
order by 1,2,3,4;
/* create one table */ /* create one table */
data &finalpks; data &finalpks;
set &pkdefault &pk4sure ; set &pkdefault &pk4sure &pkfromindex;
pk_ind=1; pk_ind=1;
/* if there are multiple unique constraints, take the first */ /* if there are multiple unique constraints, take the first */
by libref table_name constraint_name; by libref table_name constraint_name;
@@ -7560,7 +7584,8 @@ create table &outds as
iftrue=(&mdebug=0) iftrue=(&mdebug=0)
) )
%mend mp_getpk;/** %mend mp_getpk;
/**
@file @file
@brief Performs a text substitution on a file @brief Performs a text substitution on a file
@details Makes use of the GSUB function in LUA to perform a text substitution @details Makes use of the GSUB function in LUA to perform a text substitution
@@ -7952,8 +7977,8 @@ run;
%mend mp_guesspk;/** %mend mp_guesspk;/**
@file @file
@brief Returns a unique hash for a dataset @brief Returns a unique hash for a dataset
@details Ignores metadata attributes, used only to hash values. Compared @details Ignores metadata attributes, used only to hash values. If used to
datasets must be in the same order. compare datasets, they must have their columns and rows in the same order.
%mp_hashdataset(sashelp.class,outds=myhash) %mp_hashdataset(sashelp.class,outds=myhash)
@@ -7968,7 +7993,10 @@ run;
@li mf_getattrn.sas @li mf_getattrn.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mp_md5.sas
<h4> Related Files </h4>
@li mp_hashdataset.test.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@@ -7986,51 +8014,52 @@ run;
%macro mp_hashdataset( %macro mp_hashdataset(
libds, libds,
outds=, outds=work._data_,
salt=, salt=,
iftrue=%str(1=1) iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %local keyvar /* roll up the md5 */
prevkeyvar /* retain prev record md5 */
lastvar /* last var in input ds */
cvars nvars;
%if %mf_getattrn(&libds,NLOBS)=0 %then %do; %if not(%eval(%unquote(&iftrue))) %then %return;
%put %str(WARN)ING: Dataset &libds is empty, or is not a dataset;
%end; /* avoid naming conflict for hash key vars */
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do; %let keyvar=%mf_getuniquename();
%put %str(ERR)OR: Dataset &libds is not a dataset; %let prevkeyvar=%mf_getuniquename();
%end; %let lastvar=%mf_getuniquename();
%else %do;
%local keyvar /* roll up the md5 */ %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
prevkeyvar /* retain prev record md5 */ data &outds;
lastvar /* last var in input ds */ length hashkey $32;
varlist var i; retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)";
/* avoid naming conflict for hash key vars */ output;
%let keyvar=%mf_getuniquename(); stop;
%let prevkeyvar=%mf_getuniquename(); run;
%let lastvar=%mf_getuniquename(); %put &sysmacroname: Dataset &libds is empty, or is not a dataset;
%let varlist=%mf_getvarlist(&libds); %put &sysmacroname: hashkey of &outds is based on salt (&salt) only;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); %end;
length &prevkeyvar &keyvar $32; %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)"; %put %str(ERR)OR: Dataset &libds is not a dataset;
set &libds end=&lastvar; %end;
/* hash should include previous row */ %else %do;
&keyvar=put(md5(&prevkeyvar data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err;
/* loop every column, hashing every individual value */ length &prevkeyvar &keyvar $32;
%do i=1 %to %sysfunc(countw(&varlist)); retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
%let var=%scan(&varlist,&i,%str( )); set &libds end=&lastvar;
%if %mf_getvartype(&libds,&var)=C %then %do; /* hash should include previous row */
!!put(md5(trim(&var)),$hex32.) &keyvar=%mp_md5(
%end; cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar,
%else %do; nvars=%mf_getvarlist(&libds,typefilter=N)
!!put(md5(trim(put(&var*1,binary64.))),$hex32.) );
%end; &prevkeyvar=&keyvar;
%end; if &lastvar then output;
),$hex32.); run;
&prevkeyvar=&keyvar; %end;
if &lastvar then output; %mend mp_hashdataset;
run; /**
%end;
%mend mp_hashdataset;/**
@file @file
@brief Performs a wrapped \%include @brief Performs a wrapped \%include
@details This macro wrapper is necessary if you need your included code to @details This macro wrapper is necessary if you need your included code to
@@ -8415,8 +8444,15 @@ options
prxchange('s/'!!'0A'x!!'/\n/',-1, prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1, prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1, prxchange('s/'!!'09'x!!'/\t/',-1,
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
)))))!!'"'; ))))))))))))!!'"';
%end; %end;
%end; %end;
run; run;
@@ -11573,12 +11609,20 @@ run;
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do; %else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_;
rc=stpsrv_header('Content-type','text/html');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%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/html"
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/html)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=TEXT %then %do;
@@ -13358,8 +13402,8 @@ run;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@param libref the libref (not name) of the metadata library @param [in] libref The libref (not name) of the metadata library
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will @param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return silently return
@returns libname statement @returns libname statement
@@ -13373,11 +13417,11 @@ run;
libref libref
,mAbort=HARD ,mAbort=HARD
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do; %if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_; data _null_;
length liburi LibName $200; length liburi LibName msg $200;
call missing(of _all_); call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi); nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do; if nobj=1 then do;
@@ -13391,7 +13435,24 @@ run;
* not always helpful though. One example, previously received: * not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX. * NOTE: Libref XX refers to the same library metadata as libref XX.
*/ */
call symputx('msg',sysmsg(),'l'); msg=sysmsg();
if msg=:'ERROR: Libref SAVE is not assigned.' then do;
msg=catx(" ",
"Could not assign %upcase(&libref).",
"Please check metadata permissions! Libname:",libname,
"Liburi:",liburi
);
end;
else if msg="ERROR: User does not have appropriate authorization "!!
"level for library SAVE."
then do;
msg=catx(" ",
"ERROR: User does not have appropriate authorization level",
"for library %upcase(&libref), libname:",libname,
"Liburi:",liburi
);
end;
call symputx('msg',msg,'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
else do; else do;
@@ -13410,22 +13471,18 @@ run;
end; end;
run; run;
%if &mp_abort=1 %then %do; %put NOTE: &msg;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=&msg
)
%return;
%end;
%else %if %length(&msg)>2 %then %do;
%put NOTE: &msg;
%return;
%end;
%end; %end;
%else %do; %else %do;
%put NOTE: Library &libref is already assigned; %put NOTE: Library &libref is already assigned;
%end; %end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib; %mend mm_assignlib;
/** /**
@file @file
@@ -14912,8 +14969,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -15097,14 +15161,16 @@ data _null_;
put ' put '',"_METAPERSON": '' _METAPERSON; '; put ' put '',"_METAPERSON": '' _METAPERSON; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; '; put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; '; put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; '; put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; '; put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); '; put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; '; put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; '; put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; '; put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; '; put ' length memsize $32; ';
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; '; put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
@@ -18634,14 +18700,16 @@ run;
put ',"_METAPERSON": ' _METAPERSON; put ',"_METAPERSON": ' _METAPERSON;
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" "; put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" "; put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" "; put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32; length memsize $32;
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
@@ -18984,6 +19052,9 @@ run;
@param [out] outref= (msgetfil) The fileref to contain the file. @param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
**/ **/
@@ -18992,15 +19063,21 @@ run;
,mdebug=0 ,mdebug=0
); );
filename &outref temp; /* use the recfm in a separate fileref to avoid issues with subsequent reads */
%local binaryfref floc;
%let binaryfref=%mf_getuniquefileref();
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
filename &outref "&floc";
filename &binaryfref "&floc" recfm=n;
proc http method='GET' out=&outref proc http method='GET' out=&binaryfref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc"; url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=2; debug level=2;
%end; %end;
run; run;
filename &binaryfref clear;
%mend ms_getfile; %mend ms_getfile;
/** /**
@@ -19081,7 +19158,7 @@ run;
%end; %end;
%mend ms_runstp;/** %mend ms_runstp;/**
@file @file
@brief Send data to/from @sasjs/server @brief Send data to/from sasjs/server
@details This macro should be added to the start of each web service, @details This macro should be added to the start of each web service,
**immediately** followed by a call to: **immediately** followed by a call to:
@@ -19195,6 +19272,7 @@ run;
data _null_; data _null_;
set &tempds; set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */ if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');
@@ -19227,7 +19305,8 @@ run;
put ",""_DEBUG"" : ""&_debug"" "; put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG'))); SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG; put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
@@ -19242,7 +19321,8 @@ run;
put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" "; put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length autoexec $512; length autoexec $512;
autoexec=quote(urlencode(trim(getoption('autoexec')))); autoexec=quote(urlencode(trim(getoption('autoexec'))));
@@ -20373,8 +20453,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -20447,7 +20534,7 @@ data _null_;
put ' sasjs_tables SYS_JES_JOB_URI; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
put ' '; put ' ';
put '%local i tempds; '; put '%local i tempds table; ';
put '%let action=%upcase(&action); '; put '%let action=%upcase(&action); ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
@@ -20462,60 +20549,35 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' /* if the sasjs_tables param is passed, we expect param based upload */ '; put ' /* if the sasjs_tables param is passed, we expect param based upload */ ';
put ' %if %length(&sasjs_tables.XX)>2 %then %do; '; put ' %if %length(&sasjs_tables.X)>1 %then %do; ';
put ' filename _sasjs "%sysfunc(pathname(work))/sasjs.lua"; ';
put ' data _null_; ';
put ' file _sasjs; ';
put ' put ''s=sas.symget("sasjs_tables")''; ';
put ' put ''if(s:sub(1,7) == "%nrstr(")''; ';
put ' put ''then''; ';
put ' put '' tablist=s:sub(8,s:len()-1)''; ';
put ' put ''else''; ';
put ' put '' tablist=s''; ';
put ' put ''end''; ';
put ' put ''for i = 1,sas.countw(tablist) ''; ';
put ' put ''do ''; ';
put ' put '' tab=sas.scan(tablist,i)''; ';
put ' put '' sasdata=""''; ';
put ' put '' if (sas.symexist("sasjs"..i.."data0")==0)''; ';
put ' put '' then''; ';
put ' /* TODO - condense this logic */ ';
put ' put '' s=sas.symget("sasjs"..i.."data")''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=s''; ';
put ' put '' end''; ';
put ' put '' else''; ';
put ' put '' for d = 1, sas.symget("sasjs"..i.."data0")''; ';
put ' put '' do''; ';
put ' put '' s=sas.symget("sasjs"..i.."data"..d)''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=sasdata..s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=sasdata..s''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")''; ';
put ' put '' io.output(file)''; ';
put ' put '' io.write(sasdata)''; ';
put ' put '' io.close(file)''; ';
put ' put ''end''; ';
put ' run; ';
put ' %inc _sasjs; ';
put ' '; put ' ';
put ' /* now read in the data */ '; put ' /* convert data from macro variables to datasets */ ';
put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); '; put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); ';
put ' %local table; %let table=%scan(&sasjs_tables,&i); '; put ' %let table=%scan(&sasjs_tables,&i,%str( )); ';
put ' %if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1; ';
put ' data _null_; ';
put ' file "%sysfunc(pathname(work))/&table..csv" recfm=n; ';
put ' retain nrflg 0; ';
put ' length line $32767; ';
put ' do i=1 to &&sasjs&i.data0; ';
put ' if &&sasjs&i.data0=1 then line=symget("sasjs&i.data"); ';
put ' else line=symget(cats("sasjs&i.data",i)); ';
put ' if i=1 and substr(line,1,7)=''%nrstr('' then do; ';
put ' nrflg=1; ';
put ' line=substr(line,8); ';
put ' end; ';
put ' if i=&&sasjs&i.data0 and nrflg=1 then do; ';
put ' line=substr(line,1,length(line)-1); ';
put ' end; ';
put ' put line +(-1) @; ';
put ' end; ';
put ' run; ';
put ' data _null_; '; put ' data _null_; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; '; put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; ';
put ' input; '; put ' input; ';
put ' if _n_=1 then call symputx(''input_statement'',_infile_); '; put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' list; '; put ' list; ';
put ' data &table; '; put ' data work.&table; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd '; put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
put ' termstr=crlf; '; put ' termstr=crlf; ';
put ' input &input_statement; '; put ' input &input_statement; ';
@@ -20616,13 +20678,15 @@ data _null_;
put ' put ",""_DEBUG"" : ""&_debug"" "; '; put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; '; put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; '; put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; '; put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); '; put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; '; put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; '; put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; '; put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; '; put ' length memsize $32; ';
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; '; put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
@@ -24279,7 +24343,7 @@ filename &fref1 clear;
sasjs_tables SYS_JES_JOB_URI; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131; %if %index("&_debug",log) %then %let _debug=131;
%local i tempds; %local i tempds table;
%let action=%upcase(&action); %let action=%upcase(&action);
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
@@ -24294,60 +24358,35 @@ filename &fref1 clear;
%end; %end;
/* if the sasjs_tables param is passed, we expect param based upload */ /* if the sasjs_tables param is passed, we expect param based upload */
%if %length(&sasjs_tables.XX)>2 %then %do; %if %length(&sasjs_tables.X)>1 %then %do;
filename _sasjs "%sysfunc(pathname(work))/sasjs.lua";
data _null_;
file _sasjs;
put 's=sas.symget("sasjs_tables")';
put 'if(s:sub(1,7) == "%nrstr(")';
put 'then';
put ' tablist=s:sub(8,s:len()-1)';
put 'else';
put ' tablist=s';
put 'end';
put 'for i = 1,sas.countw(tablist) ';
put 'do ';
put ' tab=sas.scan(tablist,i)';
put ' sasdata=""';
put ' if (sas.symexist("sasjs"..i.."data0")==0)';
put ' then';
/* TODO - condense this logic */
put ' s=sas.symget("sasjs"..i.."data")';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=s';
put ' end';
put ' else';
put ' for d = 1, sas.symget("sasjs"..i.."data0")';
put ' do';
put ' s=sas.symget("sasjs"..i.."data"..d)';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=sasdata..s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=sasdata..s';
put ' end';
put ' end';
put ' end';
put ' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")';
put ' io.output(file)';
put ' io.write(sasdata)';
put ' io.close(file)';
put 'end';
run;
%inc _sasjs;
/* now read in the data */ /* convert data from macro variables to datasets */
%do i=1 %to %sysfunc(countw(&sasjs_tables)); %do i=1 %to %sysfunc(countw(&sasjs_tables));
%local table; %let table=%scan(&sasjs_tables,&i); %let table=%scan(&sasjs_tables,&i,%str( ));
%if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1;
data _null_;
file "%sysfunc(pathname(work))/&table..csv" recfm=n;
retain nrflg 0;
length line $32767;
do i=1 to &&sasjs&i.data0;
if &&sasjs&i.data0=1 then line=symget("sasjs&i.data");
else line=symget(cats("sasjs&i.data",i));
if i=1 and substr(line,1,7)='%nrstr(' then do;
nrflg=1;
line=substr(line,8);
end;
if i=&&sasjs&i.data0 and nrflg=1 then do;
line=substr(line,1,length(line)-1);
end;
put line +(-1) @;
end;
run;
data _null_; data _null_;
infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
input; input;
if _n_=1 then call symputx('input_statement',_infile_); if _n_=1 then call symputx('input_statement',_infile_);
list; list;
data &table; data work.&table;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
termstr=crlf; termstr=crlf;
input &input_statement; input &input_statement;
@@ -24448,13 +24487,15 @@ filename &fref1 clear;
put ",""_DEBUG"" : ""&_debug"" "; put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSSCPL"" : ""&sysscpl"" "; put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" "; put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32; length memsize $32;
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";

View File

@@ -85,7 +85,7 @@
%end; %end;
/* Stored Process Server web app context */ /* Stored Process Server web app context */
%if %symexist(_metaport) %if %symexist(_METAFOLDER)
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
@@ -161,12 +161,14 @@
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
data _null_; data _null_;
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg syswarningtext syserrortext $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=symget('msg'); msg=symget('msg');
%if &logline>0 %then %do; %if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg')); msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end; %end;
/* escape the escapes */
msg=tranwrd(msg,'\','\\');
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */

View File

@@ -106,7 +106,7 @@
proc compare proc compare
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist)))) base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds; compare=&ds noprint;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;

View File

@@ -152,6 +152,7 @@ run;
data &out_ds; data &out_ds;
set &out_ds; set &out_ds;
length infoname infoval $60 fref $8; length infoname infoval $60 fref $8;
if _n_=1 then call missing(fref);
rc=filename(fref,filepath); rc=filename(fref,filepath);
drop rc infoname fid i close fref; drop rc infoname fid i close fref;
if file_or_folder='file' then do; if file_or_folder='file' then do;

View File

@@ -48,6 +48,7 @@
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@cond
**/ **/
%macro mp_ds2cards(base_ds=, tgt_ds= %macro mp_ds2cards(base_ds=, tgt_ds=
@@ -219,7 +220,8 @@ data _null_;
put ' @file'; put ' @file';
put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset"; put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset";
put " @details Generated by %nrstr(%%)mp_ds2cards()"; put " @details Generated by %nrstr(%%)mp_ds2cards()";
put " Available on github.com/sasjs/core"; put " Source: https://github.com/sasjs/core";
put ' @cond ';
put '**/'; put '**/';
put "data &tgt_ds &indexes;"; put "data &tgt_ds &indexes;";
put "attrib "; put "attrib ";
@@ -264,6 +266,7 @@ data _null_;
if __lastobs then do; if __lastobs then do;
put ';;;;'; put ';;;;';
put 'run;'; put 'run;';
put '/** @endcond **/';
stop; stop;
end; end;
run; run;
@@ -283,4 +286,5 @@ quit;
%put NOTE-;%put NOTE-; %put NOTE-;%put NOTE-;
%put NOTE- %sysfunc(dequote(&cards_file.)); %put NOTE- %sysfunc(dequote(&cards_file.));
%put NOTE-;%put NOTE-; %put NOTE-;%put NOTE-;
%mend mp_ds2cards; %mend mp_ds2cards;
/** @endcond **/

View File

@@ -55,7 +55,8 @@
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks; %local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks
pkfromindex;
%let lib=%upcase(&lib); %let lib=%upcase(&lib);
%let ds=%upcase(&ds); %let ds=%upcase(&ds);
@@ -70,6 +71,7 @@
%let sum=%mf_getuniquename(prefix=getpk_sum); %let sum=%mf_getuniquename(prefix=getpk_sum);
%let pk4sure=%mf_getuniquename(prefix=getpk_pk4sure); %let pk4sure=%mf_getuniquename(prefix=getpk_pk4sure);
%let pkdefault=%mf_getuniquename(prefix=getpk_pkdefault); %let pkdefault=%mf_getuniquename(prefix=getpk_pkdefault);
%let pkfromindex=%mf_getuniquename(prefix=getpk_pkfromindex);
%let finalpks=%mf_getuniquename(prefix=getpk_finalpks); %let finalpks=%mf_getuniquename(prefix=getpk_finalpks);
%local dbg; %local dbg;
@@ -180,9 +182,23 @@ create table &ds1 as
and a.constraint_name=b.constraint_name and a.constraint_name=b.constraint_name
order by 1,2,3,4; order by 1,2,3,4;
/* extract cols from the relevant unique INDEXES */
create table &pkfromindex as
select libname as libref
,memname as table_name
,indxname as constraint_name
,indxpos as constraint_order
,name
from dictionary.indexes
where nomiss='yes' and unique='yes' and upcase(libname)="&lib"
%if &ds ne 0 %then %do;
and upcase(memname)="&ds"
%end;
order by 1,2,3,4;
/* create one table */ /* create one table */
data &finalpks; data &finalpks;
set &pkdefault &pk4sure ; set &pkdefault &pk4sure &pkfromindex;
pk_ind=1; pk_ind=1;
/* if there are multiple unique constraints, take the first */ /* if there are multiple unique constraints, take the first */
by libref table_name constraint_name; by libref table_name constraint_name;
@@ -256,4 +272,4 @@ create table &outds as
iftrue=(&mdebug=0) iftrue=(&mdebug=0)
) )
%mend mp_getpk; %mend mp_getpk;

View File

@@ -1,8 +1,8 @@
/** /**
@file @file
@brief Returns a unique hash for a dataset @brief Returns a unique hash for a dataset
@details Ignores metadata attributes, used only to hash values. Compared @details Ignores metadata attributes, used only to hash values. If used to
datasets must be in the same order. compare datasets, they must have their columns and rows in the same order.
%mp_hashdataset(sashelp.class,outds=myhash) %mp_hashdataset(sashelp.class,outds=myhash)
@@ -17,7 +17,10 @@
@li mf_getattrn.sas @li mf_getattrn.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mp_md5.sas
<h4> Related Files </h4>
@li mp_hashdataset.test.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@@ -35,48 +38,48 @@
%macro mp_hashdataset( %macro mp_hashdataset(
libds, libds,
outds=, outds=work._data_,
salt=, salt=,
iftrue=%str(1=1) iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %local keyvar /* roll up the md5 */
prevkeyvar /* retain prev record md5 */
lastvar /* last var in input ds */
cvars nvars;
%if %mf_getattrn(&libds,NLOBS)=0 %then %do; %if not(%eval(%unquote(&iftrue))) %then %return;
%put %str(WARN)ING: Dataset &libds is empty, or is not a dataset;
%end; /* avoid naming conflict for hash key vars */
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do; %let keyvar=%mf_getuniquename();
%put %str(ERR)OR: Dataset &libds is not a dataset; %let prevkeyvar=%mf_getuniquename();
%end; %let lastvar=%mf_getuniquename();
%else %do;
%local keyvar /* roll up the md5 */ %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
prevkeyvar /* retain prev record md5 */ data &outds;
lastvar /* last var in input ds */ length hashkey $32;
varlist var i; retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)";
/* avoid naming conflict for hash key vars */ output;
%let keyvar=%mf_getuniquename(); stop;
%let prevkeyvar=%mf_getuniquename(); run;
%let lastvar=%mf_getuniquename(); %put &sysmacroname: Dataset &libds is empty, or is not a dataset;
%let varlist=%mf_getvarlist(&libds); %put &sysmacroname: hashkey of &outds is based on salt (&salt) only;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); %end;
length &prevkeyvar &keyvar $32; %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)"; %put %str(ERR)OR: Dataset &libds is not a dataset;
set &libds end=&lastvar; %end;
/* hash should include previous row */ %else %do;
&keyvar=put(md5(&prevkeyvar data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err;
/* loop every column, hashing every individual value */ length &prevkeyvar &keyvar $32;
%do i=1 %to %sysfunc(countw(&varlist)); retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
%let var=%scan(&varlist,&i,%str( )); set &libds end=&lastvar;
%if %mf_getvartype(&libds,&var)=C %then %do; /* hash should include previous row */
!!put(md5(trim(&var)),$hex32.) &keyvar=%mp_md5(
%end; cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar,
%else %do; nvars=%mf_getvarlist(&libds,typefilter=N)
!!put(md5(trim(put(&var*1,binary64.))),$hex32.) );
%end; &prevkeyvar=&keyvar;
%end; if &lastvar then output;
),$hex32.); run;
&prevkeyvar=&keyvar; %end;
if &lastvar then output; %mend mp_hashdataset;
run;
%end;
%mend mp_hashdataset;

View File

@@ -203,8 +203,15 @@
prxchange('s/'!!'0A'x!!'/\n/',-1, prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1, prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1, prxchange('s/'!!'09'x!!'/\t/',-1,
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
)))))!!'"'; ))))))))))))!!'"';
%end; %end;
%end; %end;
run; run;

View File

@@ -105,12 +105,20 @@ run;
%end; %end;
%end; %end;
%else %if &contentype=HTML %then %do; %else %if &contentype=HTML %then %do;
%if &platform=SASVIYA %then %do; %if (&platform=SASMETA and &streamweb=1) %then %do;
data _null_;
rc=stpsrv_header('Content-type','text/html');
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
run;
%end;
%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/html"
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/html)
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
%end; %end;
%end; %end;
%else %if &contentype=TEXT %then %do; %else %if &contentype=TEXT %then %do;

View File

@@ -13,8 +13,8 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@param libref the libref (not name) of the metadata library @param [in] libref The libref (not name) of the metadata library
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will @param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return silently return
@returns libname statement @returns libname statement
@@ -28,11 +28,11 @@
libref libref
,mAbort=HARD ,mAbort=HARD
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do; %if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_; data _null_;
length liburi LibName $200; length liburi LibName msg $200;
call missing(of _all_); call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi); nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do; if nobj=1 then do;
@@ -46,7 +46,24 @@
* not always helpful though. One example, previously received: * not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX. * NOTE: Libref XX refers to the same library metadata as libref XX.
*/ */
call symputx('msg',sysmsg(),'l'); msg=sysmsg();
if msg=:'ERROR: Libref SAVE is not assigned.' then do;
msg=catx(" ",
"Could not assign %upcase(&libref).",
"Please check metadata permissions! Libname:",libname,
"Liburi:",liburi
);
end;
else if msg="ERROR: User does not have appropriate authorization "!!
"level for library SAVE."
then do;
msg=catx(" ",
"ERROR: User does not have appropriate authorization level",
"for library %upcase(&libref), libname:",libname,
"Liburi:",liburi
);
end;
call symputx('msg',msg,'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
else do; else do;
@@ -65,20 +82,16 @@
end; end;
run; run;
%if &mp_abort=1 %then %do; %put NOTE: &msg;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=&msg
)
%return;
%end;
%else %if %length(&msg)>2 %then %do;
%put NOTE: &msg;
%return;
%end;
%end; %end;
%else %do; %else %do;
%put NOTE: Library &libref is already assigned; %put NOTE: Library &libref is already assigned;
%end; %end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib; %mend mm_assignlib;

View File

@@ -236,8 +236,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -421,14 +428,16 @@ data _null_;
put ' put '',"_METAPERSON": '' _METAPERSON; '; put ' put '',"_METAPERSON": '' _METAPERSON; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; '; put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; '; put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; '; put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; '; put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); '; put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; '; put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; '; put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; '; put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; '; put ' length memsize $32; ';
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; '; put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';

View File

@@ -157,14 +157,16 @@
put ',"_METAPERSON": ' _METAPERSON; put ',"_METAPERSON": ' _METAPERSON;
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" "; put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" "; put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" "; put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32; length memsize $32;
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";

2450
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,14 +26,16 @@
"homepage": "https://core.sasjs.io", "homepage": "https://core.sasjs.io",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "sasjs cbd -t viya", "build": "sasjs cbd -t server",
"docs": "sasjs doc -t docsonly && ./sasjs/utils/build.sh", "docs": "sasjs doc -t docsonly && ./sasjs/utils/build.sh",
"test": "sasjs test -t viya", "test": "sasjs test -t server",
"lint": "sasjs lint", "lint": "sasjs lint",
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true" "prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
}, },
"devDependencies": { "devDependencies": {
"@sasjs/cli": "3.6.0", "@sasjs/cli": "3.13.0"
"@sasjs/core": "4.4.7" },
"dependencies": {
"@sasjs/core": "^4.18.13"
} }
} }

View File

@@ -4,11 +4,8 @@
"base", "base",
"ddl", "ddl",
"fcmp", "fcmp",
"meta",
"metax",
"server",
"viya",
"lua", "lua",
"server",
"tests/crossplatform", "tests/crossplatform",
"tests/ddl" "tests/ddl"
], ],
@@ -28,25 +25,20 @@
"mcTestAppLoc": "/Public/temp/macrocore" "mcTestAppLoc": "/Public/temp/macrocore"
} }
}, },
"defaultTarget": "viya", "defaultTarget": "server",
"targets": [ "targets": [
{ {
"name": "viya", "name": "viya",
"serverUrl": "https://sas.analytium.co.uk", "serverUrl": "",
"serverType": "SASVIYA", "serverType": "SASVIYA",
"httpsAgentOptions": { "httpsAgentOptions": {
"allowInsecureRequests": false "allowInsecureRequests": false
}, },
"appLoc": "/Public/temp/macrocore", "appLoc": "/Public/app/macrocore",
"macroFolders": [ "macroFolders": [
"viya",
"tests/viyaonly" "tests/viyaonly"
], ],
"programFolders": [],
"binaryFolders": [],
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
},
"contextName": "SAS Job Execution compute context" "contextName": "SAS Job Execution compute context"
}, },
{ {
@@ -58,6 +50,8 @@
}, },
"appLoc": "/Shared Data/temp/macrocore", "appLoc": "/Shared Data/temp/macrocore",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"tests/sas9only" "tests/sas9only"
], ],
"programFolders": [], "programFolders": [],
@@ -78,6 +72,7 @@
}, },
"appLoc": "/sasjs/core", "appLoc": "/sasjs/core",
"macroFolders": [ "macroFolders": [
"server",
"tests/serveronly" "tests/serveronly"
], ],
"programFolders": [], "programFolders": [],
@@ -92,6 +87,10 @@
"serverType": "SAS9", "serverType": "SAS9",
"appLoc": "dummy", "appLoc": "dummy",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"server",
"viya",
"tests/sas9only", "tests/sas9only",
"tests/viyaonly" "tests/viyaonly"
] ]
@@ -102,6 +101,7 @@
"serverType": "SASVIYA", "serverType": "SASVIYA",
"appLoc": "/Public/temp/macrocore", "appLoc": "/Public/temp/macrocore",
"macroFolders": [ "macroFolders": [
"viya",
"tests/viyaonly" "tests/viyaonly"
], ],
"deployConfig": { "deployConfig": {
@@ -110,4 +110,4 @@
"contextName": "SAS Job Execution compute context" "contextName": "SAS Job Execution compute context"
} }
] ]
} }

View File

@@ -11,6 +11,9 @@
@param [out] outref= (msgetfil) The fileref to contain the file. @param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
**/ **/
@@ -19,14 +22,20 @@
,mdebug=0 ,mdebug=0
); );
filename &outref temp; /* use the recfm in a separate fileref to avoid issues with subsequent reads */
%local binaryfref floc;
%let binaryfref=%mf_getuniquefileref();
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
filename &outref "&floc";
filename &binaryfref "&floc" recfm=n;
proc http method='GET' out=&outref proc http method='GET' out=&binaryfref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc"; url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=2; debug level=2;
%end; %end;
run; run;
filename &binaryfref clear;
%mend ms_getfile; %mend ms_getfile;

View File

@@ -1,6 +1,6 @@
/** /**
@file @file
@brief Send data to/from @sasjs/server @brief Send data to/from sasjs/server
@details This macro should be added to the start of each web service, @details This macro should be added to the start of each web service,
**immediately** followed by a call to: **immediately** followed by a call to:
@@ -114,6 +114,7 @@
data _null_; data _null_;
set &tempds; set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */ if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');
@@ -146,7 +147,8 @@
put ",""_DEBUG"" : ""&_debug"" "; put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG'))); SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG; put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
@@ -161,7 +163,8 @@
put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" "; put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length autoexec $512; length autoexec $512;
autoexec=quote(urlencode(trim(getoption('autoexec')))); autoexec=quote(urlencode(trim(getoption('autoexec'))));

View File

@@ -88,4 +88,50 @@ run;
/* constraint capture at library level is functional - uses first 2 tests */ /* constraint capture at library level is functional - uses first 2 tests */
%mp_getpk(work,outds=test4) %mp_getpk(work,outds=test4)
%mp_assertdsobs(work.test4,test=ATLEAST 2) %mp_assertdsobs(work.test4,test=ATLEAST 2)
/* unique & not null INDEX captured */
proc sql;
create table work.example5(
TX_FROM float format=datetime19.,
DD_TYPE char(16),
DD_SOURCE char(2048),
DD_SHORTDESC char(256)
);
proc datasets lib=work noprint;
modify example5;
index create tx_from /nomiss unique;
quit;
%mp_getpk(work,ds=example5,outds=test5)
data _null_;
set work.test5;
call symputx('test5',pk_fields);
run;
%mp_assert(
iftrue=("&test5"="TX_FROM"),
desc=mp_getpk captures single column not null unique index,
outds=work.test_results
)
/* unique & not null COMPOSITE INDEX captured */
proc sql;
create table work.example6(
TX_FROM float format=datetime19.,
DD_TYPE char(16),
DD_SOURCE char(2048),
DD_SHORTDESC char(256)
);
proc datasets lib=work noprint;
modify example6;
index create pk_6=(tx_from dd_type) /nomiss unique;
quit;
%mp_getpk(work,ds=example6,outds=test6)
data _null_;
set work.test6;
call symputx('test6',pk_fields);
run;
%mp_assert(
iftrue=("&test6"="TX_FROM DD_TYPE"),
desc=mp_getpk captures multiple column not null unique index,
outds=work.test_results
)

View File

@@ -0,0 +1,61 @@
/**
@file
@brief Testing mp_hashdataset.sas macro
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_hashdataset.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* test 1 - regular DS */
data work.test;
set sashelp.vextfl;
missval=.;
misscval='';
run;
%mp_assertscope(SNAPSHOT)
%mp_hashdataset(test)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(&syscc=0),
desc=Regular test works,
outds=work.test_results
)
%mp_hashdataset(test,outds=work.test2)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with output runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test2)=1),
desc=output has 1 row,
outds=work.test_results
)
data work.test3a;
set work.test;
stop;
run;
%mp_hashdataset(test3a,outds=work.test3b)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with zero-row input runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test3b)=1),
desc=test 3 output has 1 row,
outds=work.test_results
)

View File

@@ -1,15 +1,33 @@
/** /**
@file @file
@brief Testing mm_webout macro @brief Testing mv_webout macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mv_webout.sas @li mv_webout.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertdsobs.sas
**/ **/
/* testing FETCHing (WEB approach) */
data _null_;
call symputx('sasjs1data','area:$char4.'!!'0d0a'x!!'Adak');
call symputx('sasjs_tables','areas');
run;
%put &=sasjs1data;
%mv_webout(FETCH)
%mp_assertdsobs(work.areas,
desc=Test input table has 1 row,
test=EQUALS 1,
outds=work.test_results
)
%let fref=%mf_getuniquefileref(); %let fref=%mf_getuniquefileref();
%global _metaperson; %global _metaperson;
data some datasets; data some datasets;
@@ -38,4 +56,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(%str(&checkval)=%str(&sysvlong)), iftrue=(%str(&checkval)=%str(&sysvlong)),
desc=Check if the sysvlong value was created desc=Check if the sysvlong value was created
) )

View File

@@ -380,8 +380,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -454,7 +461,7 @@ data _null_;
put ' sasjs_tables SYS_JES_JOB_URI; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
put ' '; put ' ';
put '%local i tempds; '; put '%local i tempds table; ';
put '%let action=%upcase(&action); '; put '%let action=%upcase(&action); ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
@@ -469,60 +476,35 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' /* if the sasjs_tables param is passed, we expect param based upload */ '; put ' /* if the sasjs_tables param is passed, we expect param based upload */ ';
put ' %if %length(&sasjs_tables.XX)>2 %then %do; '; put ' %if %length(&sasjs_tables.X)>1 %then %do; ';
put ' filename _sasjs "%sysfunc(pathname(work))/sasjs.lua"; ';
put ' data _null_; ';
put ' file _sasjs; ';
put ' put ''s=sas.symget("sasjs_tables")''; ';
put ' put ''if(s:sub(1,7) == "%nrstr(")''; ';
put ' put ''then''; ';
put ' put '' tablist=s:sub(8,s:len()-1)''; ';
put ' put ''else''; ';
put ' put '' tablist=s''; ';
put ' put ''end''; ';
put ' put ''for i = 1,sas.countw(tablist) ''; ';
put ' put ''do ''; ';
put ' put '' tab=sas.scan(tablist,i)''; ';
put ' put '' sasdata=""''; ';
put ' put '' if (sas.symexist("sasjs"..i.."data0")==0)''; ';
put ' put '' then''; ';
put ' /* TODO - condense this logic */ ';
put ' put '' s=sas.symget("sasjs"..i.."data")''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=s''; ';
put ' put '' end''; ';
put ' put '' else''; ';
put ' put '' for d = 1, sas.symget("sasjs"..i.."data0")''; ';
put ' put '' do''; ';
put ' put '' s=sas.symget("sasjs"..i.."data"..d)''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=sasdata..s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=sasdata..s''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")''; ';
put ' put '' io.output(file)''; ';
put ' put '' io.write(sasdata)''; ';
put ' put '' io.close(file)''; ';
put ' put ''end''; ';
put ' run; ';
put ' %inc _sasjs; ';
put ' '; put ' ';
put ' /* now read in the data */ '; put ' /* convert data from macro variables to datasets */ ';
put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); '; put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); ';
put ' %local table; %let table=%scan(&sasjs_tables,&i); '; put ' %let table=%scan(&sasjs_tables,&i,%str( )); ';
put ' %if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1; ';
put ' data _null_; ';
put ' file "%sysfunc(pathname(work))/&table..csv" recfm=n; ';
put ' retain nrflg 0; ';
put ' length line $32767; ';
put ' do i=1 to &&sasjs&i.data0; ';
put ' if &&sasjs&i.data0=1 then line=symget("sasjs&i.data"); ';
put ' else line=symget(cats("sasjs&i.data",i)); ';
put ' if i=1 and substr(line,1,7)=''%nrstr('' then do; ';
put ' nrflg=1; ';
put ' line=substr(line,8); ';
put ' end; ';
put ' if i=&&sasjs&i.data0 and nrflg=1 then do; ';
put ' line=substr(line,1,length(line)-1); ';
put ' end; ';
put ' put line +(-1) @; ';
put ' end; ';
put ' run; ';
put ' data _null_; '; put ' data _null_; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; '; put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; ';
put ' input; '; put ' input; ';
put ' if _n_=1 then call symputx(''input_statement'',_infile_); '; put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' list; '; put ' list; ';
put ' data &table; '; put ' data work.&table; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd '; put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
put ' termstr=crlf; '; put ' termstr=crlf; ';
put ' input &input_statement; '; put ' input &input_statement; ';
@@ -623,13 +605,15 @@ data _null_;
put ' put ",""_DEBUG"" : ""&_debug"" "; '; put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; '; put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; '; put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; '; put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); '; put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; '; put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; '; put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; '; put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; '; put ' length memsize $32; ';
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; '; put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';

View File

@@ -49,7 +49,7 @@
sasjs_tables SYS_JES_JOB_URI; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131; %if %index("&_debug",log) %then %let _debug=131;
%local i tempds; %local i tempds table;
%let action=%upcase(&action); %let action=%upcase(&action);
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
@@ -64,60 +64,35 @@
%end; %end;
/* if the sasjs_tables param is passed, we expect param based upload */ /* if the sasjs_tables param is passed, we expect param based upload */
%if %length(&sasjs_tables.XX)>2 %then %do; %if %length(&sasjs_tables.X)>1 %then %do;
filename _sasjs "%sysfunc(pathname(work))/sasjs.lua";
data _null_;
file _sasjs;
put 's=sas.symget("sasjs_tables")';
put 'if(s:sub(1,7) == "%nrstr(")';
put 'then';
put ' tablist=s:sub(8,s:len()-1)';
put 'else';
put ' tablist=s';
put 'end';
put 'for i = 1,sas.countw(tablist) ';
put 'do ';
put ' tab=sas.scan(tablist,i)';
put ' sasdata=""';
put ' if (sas.symexist("sasjs"..i.."data0")==0)';
put ' then';
/* TODO - condense this logic */
put ' s=sas.symget("sasjs"..i.."data")';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=s';
put ' end';
put ' else';
put ' for d = 1, sas.symget("sasjs"..i.."data0")';
put ' do';
put ' s=sas.symget("sasjs"..i.."data"..d)';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=sasdata..s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=sasdata..s';
put ' end';
put ' end';
put ' end';
put ' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")';
put ' io.output(file)';
put ' io.write(sasdata)';
put ' io.close(file)';
put 'end';
run;
%inc _sasjs;
/* now read in the data */ /* convert data from macro variables to datasets */
%do i=1 %to %sysfunc(countw(&sasjs_tables)); %do i=1 %to %sysfunc(countw(&sasjs_tables));
%local table; %let table=%scan(&sasjs_tables,&i); %let table=%scan(&sasjs_tables,&i,%str( ));
%if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1;
data _null_;
file "%sysfunc(pathname(work))/&table..csv" recfm=n;
retain nrflg 0;
length line $32767;
do i=1 to &&sasjs&i.data0;
if &&sasjs&i.data0=1 then line=symget("sasjs&i.data");
else line=symget(cats("sasjs&i.data",i));
if i=1 and substr(line,1,7)='%nrstr(' then do;
nrflg=1;
line=substr(line,8);
end;
if i=&&sasjs&i.data0 and nrflg=1 then do;
line=substr(line,1,length(line)-1);
end;
put line +(-1) @;
end;
run;
data _null_; data _null_;
infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
input; input;
if _n_=1 then call symputx('input_statement',_infile_); if _n_=1 then call symputx('input_statement',_infile_);
list; list;
data &table; data work.&table;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
termstr=crlf; termstr=crlf;
input &input_statement; input &input_statement;
@@ -218,13 +193,15 @@
put ",""_DEBUG"" : ""&_debug"" "; put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" "; syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSSCPL"" : ""&sysscpl"" "; put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" "; put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong'))); sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong; put ',"SYSVLONG" : ' sysvlong;
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" '; put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32; length memsize $32;
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";