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

Compare commits

..

5 Commits

Author SHA1 Message Date
munja
cdf339d077 fix: reduce logging when debug is off 2022-06-29 20:09:00 +01:00
Allan Bowe
31702df19b Merge pull request #268 from sasjs/allanbowe/stored-process-returns-267
fix: removing endsas for 9.4m6+ WIN enviornments in mp_abort
2022-06-28 15:47:31 +02:00
Allan Bowe
cf0d1c0473 fix: removing endsas for 9.4m6+ WIN enviornments in mp_abort 2022-06-28 13:46:07 +00:00
Allan Bowe
1f369f9848 Merge pull request #266 from sasjs/latin9fixes
fix: writing utf-8 to _webout on windows in a latin9 session causes problems
2022-06-26 23:16:59 +02:00
munja
2372ff5f4f fix: writing utf-8 to _webout on windows in a latin9 session causes problems with subsequent (regular) put statements. The workaround is to write to a different file and stream it back to _webout. 2022-06-26 22:09:54 +01:00
9 changed files with 539 additions and 182 deletions

361
all.sas
View File

@@ -2191,8 +2191,10 @@ Usage:
The method used varies according to the context. Important points: The method used varies according to the context. Important points:
@li should not use endsas or abort cancel in 9.4m3 environments as this can @li should not use endsas or abort cancel in 9.4m3 WIN environments as this
cause hung multibridge sessions and result in a frozen STP server can cause hung multibridge sessions and result in a frozen STP server
@li The use of endsas in 9.4m6+ windows environments for POST requests to the
STP server can result in an empty response body
@li should not use endsas in viya 3.5 as this destroys the session and cannot @li should not use endsas in viya 3.5 as this destroys the session and cannot
fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will
recognise this and fetch the log of the parent session instead) recognise this and fetch the log of the parent session instead)
@@ -2204,8 +2206,8 @@ Usage:
a macro. For that, we recommend you use mp_include.sas to perform the a macro. For that, we recommend you use mp_include.sas to perform the
include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie, include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie,
OUTSIDE of the top-parent macro). OUTSIDE of the top-parent macro).
The soft abort has also been found to be ineffective in 9.4m6 windows The soft abort has become ineffective in 9.4m6 WINDOWS environments. We are
environments and above, so in these cases, endsas is used. currently investigating approaches to deal with this.
@param mac= (mp_abort.sas) To contain the name of the calling macro. Do not @param mac= (mp_abort.sas) To contain the name of the calling macro. Do not
@@ -2430,6 +2432,7 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
call symputx("syscc",0,"g"); call symputx("syscc",0,"g");
run; run;
%if &sysscp=WIN %if &sysscp=WIN
and 1=0 /* deprecating this logic until we figure out a consistent abort */
and "%substr(%str(&sysvlong ),1,8)"="9.04.01M" and "%substr(%str(&sysvlong ),1,8)"="9.04.01M"
and "%substr(%str(&sysvlong ),9,1)">"5" %then %do; and "%substr(%str(&sysvlong ),9,1)">"5" %then %do;
/* skip approach (below) does not work in windows m6+ envs */ /* skip approach (below) does not work in windows m6+ envs */
@@ -8575,7 +8578,12 @@ options
/** /**
@file mp_jsonout.sas @file mp_jsonout.sas
@brief Writes JSON in SASjs format to a fileref @brief Writes JSON in SASjs format to a fileref
@details PROC JSON is faster but will produce errs like the ones below if @details This macro can be used to OPEN a JSON stream and send one or more
tables as arrays of rows, where each row can be an object or a nested array.
There are two engines available - DATASTEP or PROCJSON.
PROC JSON is fast but will produce errs like the ones below if
special chars are encountered. special chars are encountered.
> (ERR)OR: Some code points did not transcode. > (ERR)OR: Some code points did not transcode.
@@ -8586,6 +8594,10 @@ options
If this happens, try running with ENGINE=DATASTEP. If this happens, try running with ENGINE=DATASTEP.
The DATASTEP engine is used to handle special SAS missing numerics, and
can also convert entire datasets to formatted values. Output JSON is always
in UTF-8.
Usage: Usage:
filename tmp temp; filename tmp temp;
@@ -8649,9 +8661,23 @@ options
run; run;
%end; %end;
%else %if (&action=ARR or &action=OBJ) %then %do; %else %if (&action=ARR or &action=OBJ) %then %do;
/* force variable names to always be uppercase in the JSON */
options validvarname=upcase; options validvarname=upcase;
data _null_; file &jref encoding='utf-8' mod; /* To avoid issues with _webout on EBI - such as encoding diffs and truncation
(https://support.sas.com/kb/49/325.html) we use temporary files */
filename _sjs1 temp lrecl=200 ;
data _null_; file _sjs1 encoding='utf-8';
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjs1 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs1 clear;
/* grab col defs */ /* grab col defs */
proc contents noprint data=&ds proc contents noprint data=&ds
@@ -8708,10 +8734,20 @@ options
data &tempds;set &ds; data &tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */ /* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty filename _sjs2 temp lrecl=131068 encoding='utf-8';
proc json out=_sjs2 pretty
%if &action=ARR %then nokeys ; %if &action=ARR %then nokeys ;
;export &tempds / nosastags fmtnumeric; ;export &tempds / nosastags fmtnumeric;
run; run;
/* send back to webout */
data _null_;
infile _sjs2 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs2 clear;
%end; %end;
%else %if &engine=DATASTEP %then %do; %else %if &engine=DATASTEP %then %do;
%datastep: %datastep:
@@ -8794,10 +8830,9 @@ options
%end; %end;
run; run;
/* write to temp loc to avoid _webout truncation filename _sjs3 temp lrecl=131068 ;
- https://support.sas.com/kb/49/325.html */ data _null_;
filename _sjs temp lrecl=131068 encoding='utf-8'; file _sjs3 encoding='utf-8';
data _null_; file _sjs lrecl=131068 encoding='utf-8' mod ;
if _n_=1 then put "["; if _n_=1 then put "[";
set &tempds; set &tempds;
if _n_>1 then put "," @; put if _n_>1 then put "," @; put
@@ -8808,27 +8843,29 @@ options
"&&name&i"n /* name literal for reserved variable names */ "&&name&i"n /* name literal for reserved variable names */
%end; %end;
%if &action=ARR %then "]" ; %else "}" ; ; %if &action=ARR %then "]" ; %else "}" ; ;
/* now write the long strings to _webout 1 char at a time */
/* close out the table */
data _null_; data _null_;
infile _sjs lrecl=1 recfm=n; file _sjs3 mod encoding='utf-8';
put ']';
run;
data _null_;
infile _sjs3 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n; file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@; input sourcechar $char1. @@;
format sourcechar hex2.; format sourcechar hex2.;
put sourcechar char1. @@; put sourcechar char1. @@;
run; run;
/* close out the table */ filename _sjs3 clear;
data _null_;
file &jref mod;
put ']';
run;
filename _sjs clear;
%end; %end;
proc sql; proc sql;
drop table &colinfo, &tempds; drop table &colinfo, &tempds;
%if &showmeta=YES %then %do; %if &showmeta=YES %then %do;
data _null_; file &jref encoding='utf-8' mod; filename _sjs4 temp lrecl=131068 encoding='utf-8';
data _null_;
file _sjs4;
put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{";
do i=1 to &numcols; do i=1 to &numcols;
name=quote(trim(symget(cats('name',i)))); name=quote(trim(symget(cats('name',i))));
@@ -8842,6 +8879,15 @@ options
end; end;
put '}}'; put '}}';
run; run;
/* send back to webout */
data _null_;
infile _sjs4 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs4 clear;
%end; %end;
%end; %end;
@@ -15026,9 +15072,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -15085,10 +15145,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -15171,10 +15241,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -15185,27 +15254,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -15219,6 +15290,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -15320,6 +15400,8 @@ data _null_;
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
put ' filename _sjsref temp lrecl=131068; ';
put ' %if %str(&_debug) ge 131 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
put ' /* if debug mode, send back first 10 records of each work table also */ '; put ' /* if debug mode, send back first 10 records of each work table also */ ';
put ' options obs=10; '; put ' options obs=10; ';
@@ -15333,11 +15415,11 @@ data _null_;
put ' i+1; '; put ' i+1; ';
put ' call symputx(cats(''wt'',i),name,''l''); '; put ' call symputx(cats(''wt'',i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); '; put ' call symputx(''wtcnt'',i,''l''); ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put ",""WORK"":{"; '; put ' put ",""WORK"":{"; ';
put ' %do i=1 %to &wtcnt; '; put ' %do i=1 %to &wtcnt; ';
put ' %let wt=&&wt&i; '; put ' %let wt=&&wt&i; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' dsid=open("WORK.&wt",''is''); '; put ' dsid=open("WORK.&wt",''is''); ';
put ' nlobs=attrn(dsid,''NLOBS''); '; put ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); '; put ' nvars=attrn(dsid,''NVARS''); ';
@@ -15346,16 +15428,16 @@ data _null_;
put ' put " ""&wt"" : {"; '; put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; '; put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; '; put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) '; put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES) ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' %end; '; put ' %end; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' run; '; put ' run; ';
put ' %end; '; put ' %end; ';
put ' /* close off json */ '; put ' /* close off json */ ';
put ' data _null_;file &fref mod encoding=''utf-8''; '; put ' data _null_;file _sjsref mod encoding=''utf-8''; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); '; put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; '; put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; '; put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
@@ -15387,6 +15469,16 @@ data _null_;
put ' put ''>>weboutEND<<''; '; put ' put ''>>weboutEND<<''; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjsref lrecl=1 recfm=n; ';
put ' file &fref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjsref clear; ';
put ' ';
put '%end; '; put '%end; ';
put ' '; put ' ';
put '%mend mm_webout; '; put '%mend mm_webout; ';
@@ -17212,7 +17304,7 @@ data _null_;
cnt=1; cnt=1;
do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0); do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0);
rc=metadata_getattr(tsuri,"Name",value); rc=metadata_getattr(tsuri,"Name",value);
put tsuri= value=; &mD.put tsuri= value=;
if value="SourceCode" then do; if value="SourceCode" then do;
/* found it! */ /* found it! */
rc=metadata_getattr(tsuri,"Id",value); rc=metadata_getattr(tsuri,"Id",value);
@@ -18668,7 +18760,9 @@ data _null_;
cnt=1; cnt=1;
do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0); do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0);
rc=metadata_getattr(tsuri,"Name",value); rc=metadata_getattr(tsuri,"Name",value);
%if &mdebug=1 %then %do;
put tsuri= value=; put tsuri= value=;
%end;
if value="SourceCode" then do; if value="SourceCode" then do;
/* found it! */ /* found it! */
rc=metadata_getattr(tsuri,"Id",value); rc=metadata_getattr(tsuri,"Id",value);
@@ -18751,29 +18845,30 @@ run;
filename &frefout clear; filename &frefout clear;
%end; %end;
%mend mm_updatestpsourcecode;/** %mend mm_updatestpsourcecode;
/**
@file mm_webout.sas @file mm_webout.sas
@brief Send data to/from SAS Stored Processes @brief Send data to/from SAS Stored Processes
@details This macro should be added to the start of each Stored Process, @details This macro should be added to the start of each Stored Process,
**immediately** followed by a call to: **immediately** followed by a call to:
%mm_webout(FETCH) %mm_webout(FETCH)
This will read all the input data and create same-named SAS datasets in the This will read all the input data and create same-named SAS datasets in the
WORK library. You can then insert your code, and send data back using the WORK library. You can then insert your code, and send data back using the
following syntax: following syntax:
data some datasets; * make some data ; data some datasets; * make some data ;
retain some columns; retain some columns;
run; run;
%mm_webout(OPEN) %mm_webout(OPEN)
%mm_webout(ARR,some) * Array format, fast, suitable for large tables ; %mm_webout(ARR,some) * Array format, fast, suitable for large tables ;
%mm_webout(OBJ,datasets) * Object format, easier to work with ; %mm_webout(OBJ,datasets) * Object format, easier to work with ;
Finally, wrap everything up send some helpful system variables too Finally, wrap everything up send some helpful system variables too
%mm_webout(CLOSE) %mm_webout(CLOSE)
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@@ -18788,6 +18883,10 @@ run;
object with the same name as the table but prefixed with a dollar sign - ie, object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}` `,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
@@ -18864,6 +18963,8 @@ run;
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
/* To avoid issues with _webout on EBI we use a temporary file */
filename _sjsref temp lrecl=131068;
%if %str(&_debug) ge 131 %then %do; %if %str(&_debug) ge 131 %then %do;
/* if debug mode, send back first 10 records of each work table also */ /* if debug mode, send back first 10 records of each work table also */
options obs=10; options obs=10;
@@ -18877,11 +18978,11 @@ run;
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');
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put ",""WORK"":{"; put ",""WORK"":{";
%do i=1 %to &wtcnt; %do i=1 %to &wtcnt;
%let wt=&&wt&i; %let wt=&&wt&i;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
dsid=open("WORK.&wt",'is'); dsid=open("WORK.&wt",'is');
nlobs=attrn(dsid,'NLOBS'); nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS'); nvars=attrn(dsid,'NVARS');
@@ -18890,16 +18991,16 @@ run;
put " ""&wt"" : {"; put " ""&wt"" : {";
put '"nlobs":' nlobs; put '"nlobs":' nlobs;
put ',"nvars":' nvars; put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES)
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
%end; %end;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
run; run;
%end; %end;
/* close off json */ /* close off json */
data _null_;file &fref mod encoding='utf-8'; data _null_;file _sjsref mod encoding='utf-8';
_PROGRAM=quote(trim(resolve(symget('_PROGRAM')))); _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" "; put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" "; put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
@@ -18931,6 +19032,16 @@ run;
put '>>weboutEND<<'; put '>>weboutEND<<';
%end; %end;
run; run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjsref lrecl=1 recfm=n;
file &fref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjsref clear;
%end; %end;
%mend mm_webout; %mend mm_webout;
@@ -19759,9 +19870,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -19818,10 +19943,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -19904,10 +20039,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -19918,27 +20052,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -19952,6 +20088,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -22100,9 +22245,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -22159,10 +22318,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -22245,10 +22414,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -22259,27 +22427,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -22293,6 +22463,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';

View File

@@ -8,8 +8,10 @@
The method used varies according to the context. Important points: The method used varies according to the context. Important points:
@li should not use endsas or abort cancel in 9.4m3 environments as this can @li should not use endsas or abort cancel in 9.4m3 WIN environments as this
cause hung multibridge sessions and result in a frozen STP server can cause hung multibridge sessions and result in a frozen STP server
@li The use of endsas in 9.4m6+ windows environments for POST requests to the
STP server can result in an empty response body
@li should not use endsas in viya 3.5 as this destroys the session and cannot @li should not use endsas in viya 3.5 as this destroys the session and cannot
fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will
recognise this and fetch the log of the parent session instead) recognise this and fetch the log of the parent session instead)
@@ -21,8 +23,8 @@
a macro. For that, we recommend you use mp_include.sas to perform the a macro. For that, we recommend you use mp_include.sas to perform the
include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie, include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie,
OUTSIDE of the top-parent macro). OUTSIDE of the top-parent macro).
The soft abort has also been found to be ineffective in 9.4m6 windows The soft abort has become ineffective in 9.4m6 WINDOWS environments. We are
environments and above, so in these cases, endsas is used. currently investigating approaches to deal with this.
@param mac= (mp_abort.sas) To contain the name of the calling macro. Do not @param mac= (mp_abort.sas) To contain the name of the calling macro. Do not
@@ -247,6 +249,7 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
call symputx("syscc",0,"g"); call symputx("syscc",0,"g");
run; run;
%if &sysscp=WIN %if &sysscp=WIN
and 1=0 /* deprecating this logic until we figure out a consistent abort */
and "%substr(%str(&sysvlong ),1,8)"="9.04.01M" and "%substr(%str(&sysvlong ),1,8)"="9.04.01M"
and "%substr(%str(&sysvlong ),9,1)">"5" %then %do; and "%substr(%str(&sysvlong ),9,1)">"5" %then %do;
/* skip approach (below) does not work in windows m6+ envs */ /* skip approach (below) does not work in windows m6+ envs */

View File

@@ -1,7 +1,12 @@
/** /**
@file mp_jsonout.sas @file mp_jsonout.sas
@brief Writes JSON in SASjs format to a fileref @brief Writes JSON in SASjs format to a fileref
@details PROC JSON is faster but will produce errs like the ones below if @details This macro can be used to OPEN a JSON stream and send one or more
tables as arrays of rows, where each row can be an object or a nested array.
There are two engines available - DATASTEP or PROCJSON.
PROC JSON is fast but will produce errs like the ones below if
special chars are encountered. special chars are encountered.
> (ERR)OR: Some code points did not transcode. > (ERR)OR: Some code points did not transcode.
@@ -12,6 +17,10 @@
If this happens, try running with ENGINE=DATASTEP. If this happens, try running with ENGINE=DATASTEP.
The DATASTEP engine is used to handle special SAS missing numerics, and
can also convert entire datasets to formatted values. Output JSON is always
in UTF-8.
Usage: Usage:
filename tmp temp; filename tmp temp;
@@ -75,9 +84,23 @@
run; run;
%end; %end;
%else %if (&action=ARR or &action=OBJ) %then %do; %else %if (&action=ARR or &action=OBJ) %then %do;
/* force variable names to always be uppercase in the JSON */
options validvarname=upcase; options validvarname=upcase;
data _null_; file &jref encoding='utf-8' mod; /* To avoid issues with _webout on EBI - such as encoding diffs and truncation
(https://support.sas.com/kb/49/325.html) we use temporary files */
filename _sjs1 temp lrecl=200 ;
data _null_; file _sjs1 encoding='utf-8';
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjs1 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs1 clear;
/* grab col defs */ /* grab col defs */
proc contents noprint data=&ds proc contents noprint data=&ds
@@ -134,10 +157,20 @@
data &tempds;set &ds; data &tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */ /* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty filename _sjs2 temp lrecl=131068 encoding='utf-8';
proc json out=_sjs2 pretty
%if &action=ARR %then nokeys ; %if &action=ARR %then nokeys ;
;export &tempds / nosastags fmtnumeric; ;export &tempds / nosastags fmtnumeric;
run; run;
/* send back to webout */
data _null_;
infile _sjs2 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs2 clear;
%end; %end;
%else %if &engine=DATASTEP %then %do; %else %if &engine=DATASTEP %then %do;
%datastep: %datastep:
@@ -220,10 +253,9 @@
%end; %end;
run; run;
/* write to temp loc to avoid _webout truncation filename _sjs3 temp lrecl=131068 ;
- https://support.sas.com/kb/49/325.html */ data _null_;
filename _sjs temp lrecl=131068 encoding='utf-8'; file _sjs3 encoding='utf-8';
data _null_; file _sjs lrecl=131068 encoding='utf-8' mod ;
if _n_=1 then put "["; if _n_=1 then put "[";
set &tempds; set &tempds;
if _n_>1 then put "," @; put if _n_>1 then put "," @; put
@@ -234,27 +266,29 @@
"&&name&i"n /* name literal for reserved variable names */ "&&name&i"n /* name literal for reserved variable names */
%end; %end;
%if &action=ARR %then "]" ; %else "}" ; ; %if &action=ARR %then "]" ; %else "}" ; ;
/* now write the long strings to _webout 1 char at a time */
/* close out the table */
data _null_; data _null_;
infile _sjs lrecl=1 recfm=n; file _sjs3 mod encoding='utf-8';
put ']';
run;
data _null_;
infile _sjs3 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n; file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@; input sourcechar $char1. @@;
format sourcechar hex2.; format sourcechar hex2.;
put sourcechar char1. @@; put sourcechar char1. @@;
run; run;
/* close out the table */ filename _sjs3 clear;
data _null_;
file &jref mod;
put ']';
run;
filename _sjs clear;
%end; %end;
proc sql; proc sql;
drop table &colinfo, &tempds; drop table &colinfo, &tempds;
%if &showmeta=YES %then %do; %if &showmeta=YES %then %do;
data _null_; file &jref encoding='utf-8' mod; filename _sjs4 temp lrecl=131068 encoding='utf-8';
data _null_;
file _sjs4;
put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{";
do i=1 to &numcols; do i=1 to &numcols;
name=quote(trim(symget(cats('name',i)))); name=quote(trim(symget(cats('name',i))));
@@ -268,6 +302,15 @@
end; end;
put '}}'; put '}}';
run; run;
/* send back to webout */
data _null_;
infile _sjs4 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs4 clear;
%end; %end;
%end; %end;

View File

@@ -109,9 +109,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -168,10 +182,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -254,10 +278,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -268,27 +291,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -302,6 +327,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -403,6 +437,8 @@ data _null_;
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
put ' filename _sjsref temp lrecl=131068; ';
put ' %if %str(&_debug) ge 131 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
put ' /* if debug mode, send back first 10 records of each work table also */ '; put ' /* if debug mode, send back first 10 records of each work table also */ ';
put ' options obs=10; '; put ' options obs=10; ';
@@ -416,11 +452,11 @@ data _null_;
put ' i+1; '; put ' i+1; ';
put ' call symputx(cats(''wt'',i),name,''l''); '; put ' call symputx(cats(''wt'',i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); '; put ' call symputx(''wtcnt'',i,''l''); ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put ",""WORK"":{"; '; put ' put ",""WORK"":{"; ';
put ' %do i=1 %to &wtcnt; '; put ' %do i=1 %to &wtcnt; ';
put ' %let wt=&&wt&i; '; put ' %let wt=&&wt&i; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' dsid=open("WORK.&wt",''is''); '; put ' dsid=open("WORK.&wt",''is''); ';
put ' nlobs=attrn(dsid,''NLOBS''); '; put ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); '; put ' nvars=attrn(dsid,''NVARS''); ';
@@ -429,16 +465,16 @@ data _null_;
put ' put " ""&wt"" : {"; '; put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; '; put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; '; put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) '; put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES) ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' %end; '; put ' %end; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' run; '; put ' run; ';
put ' %end; '; put ' %end; ';
put ' /* close off json */ '; put ' /* close off json */ ';
put ' data _null_;file &fref mod encoding=''utf-8''; '; put ' data _null_;file _sjsref mod encoding=''utf-8''; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); '; put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; '; put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; '; put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
@@ -470,6 +506,16 @@ data _null_;
put ' put ''>>weboutEND<<''; '; put ' put ''>>weboutEND<<''; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjsref lrecl=1 recfm=n; ';
put ' file &fref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjsref clear; ';
put ' ';
put '%end; '; put '%end; ';
put ' '; put ' ';
put '%mend mm_webout; '; put '%mend mm_webout; ';

View File

@@ -58,7 +58,7 @@ data _null_;
cnt=1; cnt=1;
do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0); do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0);
rc=metadata_getattr(tsuri,"Name",value); rc=metadata_getattr(tsuri,"Name",value);
put tsuri= value=; &mD.put tsuri= value=;
if value="SourceCode" then do; if value="SourceCode" then do;
/* found it! */ /* found it! */
rc=metadata_getattr(tsuri,"Id",value); rc=metadata_getattr(tsuri,"Id",value);

View File

@@ -43,7 +43,9 @@ data _null_;
cnt=1; cnt=1;
do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0); do while (metadata_getnasn(uri,"Notes",cnt,tsuri)>0);
rc=metadata_getattr(tsuri,"Name",value); rc=metadata_getattr(tsuri,"Name",value);
%if &mdebug=1 %then %do;
put tsuri= value=; put tsuri= value=;
%end;
if value="SourceCode" then do; if value="SourceCode" then do;
/* found it! */ /* found it! */
rc=metadata_getattr(tsuri,"Id",value); rc=metadata_getattr(tsuri,"Id",value);
@@ -126,4 +128,4 @@ run;
filename &frefout clear; filename &frefout clear;
%end; %end;
%mend mm_updatestpsourcecode; %mend mm_updatestpsourcecode;

View File

@@ -4,23 +4,23 @@
@details This macro should be added to the start of each Stored Process, @details This macro should be added to the start of each Stored Process,
**immediately** followed by a call to: **immediately** followed by a call to:
%mm_webout(FETCH) %mm_webout(FETCH)
This will read all the input data and create same-named SAS datasets in the This will read all the input data and create same-named SAS datasets in the
WORK library. You can then insert your code, and send data back using the WORK library. You can then insert your code, and send data back using the
following syntax: following syntax:
data some datasets; * make some data ; data some datasets; * make some data ;
retain some columns; retain some columns;
run; run;
%mm_webout(OPEN) %mm_webout(OPEN)
%mm_webout(ARR,some) * Array format, fast, suitable for large tables ; %mm_webout(ARR,some) * Array format, fast, suitable for large tables ;
%mm_webout(OBJ,datasets) * Object format, easier to work with ; %mm_webout(OBJ,datasets) * Object format, easier to work with ;
Finally, wrap everything up send some helpful system variables too Finally, wrap everything up send some helpful system variables too
%mm_webout(CLOSE) %mm_webout(CLOSE)
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@@ -35,6 +35,10 @@
object with the same name as the table but prefixed with a dollar sign - ie, object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}` `,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
@@ -111,6 +115,8 @@
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
/* To avoid issues with _webout on EBI we use a temporary file */
filename _sjsref temp lrecl=131068;
%if %str(&_debug) ge 131 %then %do; %if %str(&_debug) ge 131 %then %do;
/* if debug mode, send back first 10 records of each work table also */ /* if debug mode, send back first 10 records of each work table also */
options obs=10; options obs=10;
@@ -124,11 +130,11 @@
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');
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put ",""WORK"":{"; put ",""WORK"":{";
%do i=1 %to &wtcnt; %do i=1 %to &wtcnt;
%let wt=&&wt&i; %let wt=&&wt&i;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
dsid=open("WORK.&wt",'is'); dsid=open("WORK.&wt",'is');
nlobs=attrn(dsid,'NLOBS'); nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS'); nvars=attrn(dsid,'NVARS');
@@ -137,16 +143,16 @@
put " ""&wt"" : {"; put " ""&wt"" : {";
put '"nlobs":' nlobs; put '"nlobs":' nlobs;
put ',"nvars":' nvars; put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES)
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
%end; %end;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
run; run;
%end; %end;
/* close off json */ /* close off json */
data _null_;file &fref mod encoding='utf-8'; data _null_;file _sjsref mod encoding='utf-8';
_PROGRAM=quote(trim(resolve(symget('_PROGRAM')))); _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" "; put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" "; put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
@@ -178,6 +184,16 @@
put '>>weboutEND<<'; put '>>weboutEND<<';
%end; %end;
run; run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjsref lrecl=1 recfm=n;
file &fref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjsref clear;
%end; %end;
%mend mm_webout; %mend mm_webout;

View File

@@ -110,9 +110,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -169,10 +183,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -255,10 +279,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -269,27 +292,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -303,6 +328,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';

View File

@@ -252,9 +252,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -311,10 +325,20 @@ data _null_;
put ' data &tempds;set &ds; '; put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ '; put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -397,10 +421,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -411,27 +434,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 char at a time */ '; put ' ';
put ' /* close out the table */ ';
put ' data _null_; '; put ' data _null_; ';
put ' infile _sjs lrecl=1 recfm=n; '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' put '']''; ';
put ' run; ';
put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; '; put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; '; put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; '; put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; '; put ' put sourcechar char1. @@; ';
put ' run; '; put ' run; ';
put ' /* close out the table */ '; put ' filename _sjs3 clear; ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -445,6 +470,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';