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

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.

This commit is contained in:
munja
2022-06-26 22:09:54 +01:00
parent 6d0e34ba1d
commit 2372ff5f4f
6 changed files with 516 additions and 170 deletions

View File

@@ -109,9 +109,23 @@ data _null_;
put ' run; ';
put '%end; ';
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 ' 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 ' 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 ' /* grab col defs */ ';
put ' proc contents noprint data=&ds ';
@@ -168,10 +182,20 @@ data _null_;
put ' data &tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; ';
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 ' ;export &tempds / nosastags fmtnumeric; ';
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 ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: ';
@@ -254,10 +278,9 @@ data _null_;
put ' %end; ';
put ' run; ';
put ' ';
put ' /* write to temp loc to avoid _webout truncation ';
put ' - https://support.sas.com/kb/49/325.html */ ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' filename _sjs3 temp lrecl=131068 ; ';
put ' data _null_; ';
put ' file _sjs3 encoding=''utf-8''; ';
put ' if _n_=1 then put "["; ';
put ' set &tempds; ';
put ' if _n_>1 then put "," @; put ';
@@ -268,27 +291,29 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; ';
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 ' 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 ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' /* close out the table */ ';
put ' data _null_; ';
put ' file &jref mod; ';
put ' put '']''; ';
put ' run; ';
put ' filename _sjs clear; ';
put ' filename _sjs3 clear; ';
put ' %end; ';
put ' ';
put ' proc sql; ';
put ' drop table &colinfo, &tempds; ';
put ' ';
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 ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -302,6 +327,15 @@ data _null_;
put ' end; ';
put ' put ''}}''; ';
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 ' ';
@@ -403,6 +437,8 @@ data _null_;
put ' ) ';
put '%end; ';
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 debug mode, send back first 10 records of each work table also */ ';
put ' options obs=10; ';
@@ -416,11 +452,11 @@ data _null_;
put ' i+1; ';
put ' call symputx(cats(''wt'',i),name,''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 ' %do i=1 %to &wtcnt; ';
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 ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); ';
@@ -429,16 +465,16 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES) ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' %end; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' run; ';
put ' %end; ';
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 ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
@@ -470,6 +506,16 @@ data _null_;
put ' put ''>>weboutEND<<''; ';
put ' %end; ';
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 ' ';
put '%mend mm_webout; ';

View File

@@ -4,23 +4,23 @@
@details This macro should be added to the start of each Stored Process,
**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
WORK library. You can then insert your code, and send data back using the
following syntax:
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
following syntax:
data some datasets; * make some data ;
retain some columns;
run;
data some datasets; * make some data ;
retain some columns;
run;
%mm_webout(OPEN)
%mm_webout(ARR,some) * Array format, fast, suitable for large tables ;
%mm_webout(OBJ,datasets) * Object format, easier to work with ;
%mm_webout(OPEN)
%mm_webout(ARR,some) * Array format, fast, suitable for large tables ;
%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
@@ -35,6 +35,10 @@
object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@version 9.3
@author Allan Bowe
@@ -111,6 +115,8 @@
)
%end;
%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 debug mode, send back first 10 records of each work table also */
options obs=10;
@@ -124,11 +130,11 @@
i+1;
call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l');
data _null_; file &fref mod encoding='utf-8';
data _null_; file _sjsref mod encoding='utf-8';
put ",""WORK"":{";
%do i=1 %to &wtcnt;
%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');
nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS');
@@ -137,16 +143,16 @@
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES)
data _null_; file &fref mod encoding='utf-8';
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES)
data _null_; file _sjsref mod encoding='utf-8';
put "}";
%end;
data _null_; file &fref mod encoding='utf-8';
data _null_; file _sjsref mod encoding='utf-8';
put "}";
run;
%end;
/* 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'))));
put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
@@ -178,6 +184,16 @@
put '>>weboutEND<<';
%end;
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;
%mend mm_webout;