Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mm_webout.sas
Go to the documentation of this file.
1/**
2 @file mm_webout.sas
3 @brief Send data to/from SAS Stored Processes
4 @details This macro should be added to the start of each Stored Process,
5 **immediately** followed by a call to:
6
7 %mm_webout(FETCH)
8
9 This will read all the input data and create same-named SAS datasets in the
10 WORK library. You can then insert your code, and send data back using the
11 following syntax:
12
13 data some datasets; * make some data ;
14 retain some columns;
15 run;
16
17 %mm_webout(OPEN)
18 %mm_webout(ARR,some) * Array format, fast, suitable for large tables ;
19 %mm_webout(OBJ,datasets) * Object format, easier to work with ;
20
21 Finally, wrap everything up send some helpful system variables too
22
23 %mm_webout(CLOSE)
24
25
26 @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
27 @param [in] ds The dataset to send back to the frontend
28 @param [out] dslabel= Value to use instead of table name for sending to JSON
29 @param [in] fmt= (N) Setting Y converts all vars to their formatted values
30 @param [out] fref= (_webout) The fileref to which to write the JSON
31 @param [in] missing= (NULL) Special numeric missing values can be sent as NULL
32 (eg `null`) or as STRING values (eg `".a"` or `".b"`)
33 @param [in] showmeta= (N) Set to Y to output metadata alongside each table,
34 such as the column formats and types. The metadata is contained inside an
35 object with the same name as the table but prefixed with a dollar sign - ie,
36 `,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
37 @param [in] workobs= (0) When set to a positive integer, will create a new
38 output object (WORK) which contains this number of observations from all
39 tables in the WORK library.
40 @param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
41 that should be converted to output JSON
42
43 <h4> SAS Macros </h4>
44 @li mp_jsonout.sas
45
46 <h4> Related Macros </h4>
47 @li ms_webout.sas
48 @li mv_webout.sas
49
50 @version 9.3
51 @author Allan Bowe
52
53**/
54%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL
55 ,showmeta=N,maxobs=MAX,workobs=0
56);
57%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
58 sasjs_tables;
59%local i tempds jsonengine;
60
61/* see https://github.com/sasjs/core/issues/41 */
62%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON;
63%else %let jsonengine=DATASTEP;
64
65
66%if &action=FETCH %then %do;
67 %if %str(&_debug) ge 131 %then %do;
68 options mprint notes mprintnest;
69 %end;
70 %let _webin_file_count=%eval(&_webin_file_count+0);
71 /* now read in the data */
72 %do i=1 %to &_webin_file_count;
73 %if &_webin_file_count=1 %then %do;
74 %let _webin_fileref1=&_webin_fileref;
75 %let _webin_name1=&_webin_name;
76 %end;
77 data _null_;
78 infile &&_webin_fileref&i termstr=crlf;
79 input;
80 call symputx('input_statement',_infile_);
81 putlog "&&_webin_name&i input statement: " _infile_;
82 stop;
83 data &&_webin_name&i;
84 infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding='utf-8';
85 input &input_statement;
86 %if %str(&_debug) ge 131 %then %do;
87 if _n_<20 then putlog _infile_;
88 %end;
89 run;
90 %let sasjs_tables=&sasjs_tables &&_webin_name&i;
91 %end;
92%end;
93
94%else %if &action=OPEN %then %do;
95 /* fix encoding */
96 OPTIONS NOBOMFILE;
97
98 /**
99 * check xengine type to avoid the below err message:
100 * > Function is only valid for filerefs using the CACHE access method.
101 */
102 data _null_;
103 set sashelp.vextfl(where=(fileref="_WEBOUT"));
104 if xengine='STREAM' then do;
105 rc=stpsrv_header('Content-type',"text/html; encoding=utf-8");
106 end;
107 run;
108
109 /* setup json */
110 data _null_;file &fref encoding='utf-8';
111 %if %str(&_debug) ge 131 %then %do;
112 put '>>weboutBEGIN<<';
113 %end;
114 put '{"SYSDATE" : "' "&SYSDATE" '"';
115 put ',"SYSTIME" : "' "&SYSTIME" '"';
116 run;
117
118%end;
119
120%else %if &action=ARR or &action=OBJ %then %do;
121 %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
122 ,engine=&jsonengine,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
123 )
124%end;
125%else %if &action=CLOSE %then %do;
126 /* To avoid issues with _webout on EBI we use a temporary file */
127 filename _sjsref temp lrecl=131068;
128 %if %str(&workobs) > 0 %then %do;
129 /* if debug mode, send back first XX records of each work table also */
130 data;run;%let tempds=%scan(&syslast,2,.);
131 ods output Members=&tempds;
132 proc datasets library=WORK memtype=data;
133 %local wtcnt;%let wtcnt=0;
134 data _null_;
135 set &tempds;
136 if not (upcase(name) =:"DATA"); /* ignore temp datasets */
137 i+1;
138 call symputx(cats('wt',i),name,'l');
139 call symputx('wtcnt',i,'l');
140 data _null_; file _sjsref mod encoding='utf-8';
141 put ",""WORK"":{";
142 %do i=1 %to &wtcnt;
143 %let wt=&&wt&i;
144 data _null_; file _sjsref mod encoding='utf-8';
145 dsid=open("WORK.&wt",'is');
146 nlobs=attrn(dsid,'NLOBS');
147 nvars=attrn(dsid,'NVARS');
148 rc=close(dsid);
149 if &i>1 then put ','@;
150 put " ""&wt"" : {";
151 put '"nlobs":' nlobs;
152 put ',"nvars":' nvars;
153 %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y
154 ,maxobs=&workobs
155 )
156 data _null_; file _sjsref mod encoding='utf-8';
157 put "}";
158 %end;
159 data _null_; file _sjsref mod encoding='utf-8';
160 put "}";
161 run;
162 %end;
163 /* close off json */
164 data _null_;file _sjsref mod encoding='utf-8';
165 length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
166 put ",""_DEBUG"" : ""&_debug"" ";
167 _METAUSER=quote(trim(symget('_METAUSER')));
168 put ",""_METAUSER"": " _METAUSER;
169 _METAPERSON=quote(trim(symget('_METAPERSON')));
170 put ',"_METAPERSON": ' _METAPERSON;
171 _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
172 put ',"_PROGRAM" : ' _PROGRAM ;
173 autoexec=quote(urlencode(trim(getoption('autoexec'))));
174 put ',"AUTOEXEC" : ' autoexec;
175 put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
176 put ",""SYSCC"" : ""&syscc"" ";
177 put ",""SYSENCODING"" : ""&sysencoding"" ";
178 syserrortext=cats(symget('syserrortext'));
179 if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
180 syserrortext='"'!!trim(
181 prxchange('s/"/\\"/',-1, /* double quote */
182 prxchange('s/\x0A/\n/',-1, /* new line */
183 prxchange('s/\x0D/\r/',-1, /* carriage return */
184 prxchange('s/\x09/\\t/',-1, /* tab */
185 prxchange('s/\x00/\\u0000/',-1, /* NUL */
186 prxchange('s/\x0E/\\u000E/',-1, /* SS */
187 prxchange('s/\x0F/\\u000F/',-1, /* SF */
188 prxchange('s/\x01/\\u0001/',-1, /* SOH */
189 prxchange('s/\x02/\\u0002/',-1, /* STX */
190 prxchange('s/\x10/\\u0010/',-1, /* DLE */
191 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
192 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
193 prxchange('s/\\/\\\\/',-1,syserrortext)
194 )))))))))))))!!'"';
195 end;
196 else syserrortext=cats('"',syserrortext,'"');
197 put ',"SYSERRORTEXT" : ' syserrortext;
198 put ",""SYSHOSTNAME"" : ""&syshostname"" ";
199 put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
200 put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
201 SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
202 put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
203 put ",""SYSJOBID"" : ""&sysjobid"" ";
204 put ",""SYSSCPL"" : ""&sysscpl"" ";
205 put ",""SYSSITE"" : ""&syssite"" ";
206 put ",""SYSUSERID"" : ""&sysuserid"" ";
207 sysvlong=quote(trim(symget('sysvlong')));
208 put ',"SYSVLONG" : ' sysvlong;
209 syswarningtext=cats(symget('syswarningtext'));
210 if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
211 syswarningtext='"'!!trim(
212 prxchange('s/"/\\"/',-1, /* double quote */
213 prxchange('s/\x0A/\n/',-1, /* new line */
214 prxchange('s/\x0D/\r/',-1, /* carriage return */
215 prxchange('s/\x09/\\t/',-1, /* tab */
216 prxchange('s/\x00/\\u0000/',-1, /* NUL */
217 prxchange('s/\x0E/\\u000E/',-1, /* SS */
218 prxchange('s/\x0F/\\u000F/',-1, /* SF */
219 prxchange('s/\x01/\\u0001/',-1, /* SOH */
220 prxchange('s/\x02/\\u0002/',-1, /* STX */
221 prxchange('s/\x10/\\u0010/',-1, /* DLE */
222 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
223 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
224 prxchange('s/\\/\\\\/',-1,syswarningtext)
225 )))))))))))))!!'"';
226 end;
227 else syswarningtext=cats('"',syswarningtext,'"');
228 put ',"SYSWARNINGTEXT" : ' syswarningtext;
229 put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
230 length memsize $32;
231 memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
232 memsize=quote(cats(memsize));
233 put ',"MEMSIZE" : ' memsize;
234 put "}" @;
235 %if %str(&_debug) ge 131 %then %do;
236 put '>>weboutEND<<';
237 %end;
238 run;
239 /* now write to _webout 1 char at a time */
240 data _null_;
241 infile _sjsref lrecl=1 recfm=n;
242 file &fref mod lrecl=1 recfm=n;
243 input sourcechar $char1. @@;
244 format sourcechar hex2.;
245 put sourcechar char1. @@;
246 run;
247 filename _sjsref clear;
248
249%end;
250
251%mend mm_webout;