Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
ms_webout.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Send data to/from sasjs/server
4 @details This macro should be added to the start of each web service,
5 **immediately** followed by a call to:
6
7 %ms_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 %ms_webout(OPEN)
18 %ms_webout(ARR,some) * Array format, fast, suitable for large tables ;
19 %ms_webout(OBJ,datasets) * Object format, easier to work with ;
20 %ms_webout(CLOSE)
21
22
23 @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
24 @param [in] ds The dataset to send back to the frontend
25 @param [out] dslabel= value to use instead of table name for sending to JSON
26 @param [in] fmt= (N) Setting Y converts all vars to their formatted values
27 @param [out] fref= (_webout) The fileref to which to write the JSON
28 @param [in] missing= (NULL) Special numeric missing values can be sent as NULL
29 (eg `null`) or as STRING values (eg `".a"` or `".b"`)
30 @param [in] showmeta= (N) Set to Y to output metadata alongside each table,
31 such as the column formats and types. The metadata is contained inside an
32 object with the same name as the table but prefixed with a dollar sign - ie,
33 `,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
34 @param [in] workobs= (0) When set to a positive integer, will create a new
35 output object (WORK) which contains this number of observations from all
36 tables in the WORK library.
37 @param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
38 that should be converted to output JSON
39
40 <h4> SAS Macros </h4>
41 @li mf_getuser.sas
42 @li mp_jsonout.sas
43 @li mfs_httpheader.sas
44
45 <h4> Related Macros </h4>
46 @li mv_webout.sas
47 @li mm_webout.sas
48
49 @version 9.3
50 @author Allan Bowe
51
52**/
53
54%macro ms_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
60%local i tempds;
61%let action=%upcase(&action);
62
63%if &action=FETCH %then %do;
64 %if %str(&_debug) ge 131 %then %do;
65 options mprint notes mprintnest;
66 %end;
67 %let _webin_file_count=%eval(&_webin_file_count+0);
68 /* now read in the data */
69 %do i=1 %to &_webin_file_count;
70 %if &_webin_file_count=1 %then %do;
71 %let _webin_fileref1=&_webin_fileref;
72 %let _webin_name1=&_webin_name;
73 %end;
74 data _null_;
75 infile &&_webin_fileref&i termstr=crlf lrecl=32767;
76 input;
77 /* a plain $ informat strips leading blanks - use $char instead */
78 call symputx('input_statement'
79 ,prxchange('s/:\$(?=[0-9 ])/:\$char/i',-1,_infile_)
80 );
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 lrecl=32767;
86 input &input_statement;
87 %if %str(&_debug) ge 131 %then %do;
88 if _n_<20 then putlog _infile_;
89 %end;
90 run;
91 %let sasjs_tables=&sasjs_tables &&_webin_name&i;
92 %end;
93%end;
94
95%else %if &action=OPEN %then %do;
96 /* fix encoding and ensure enough lrecl */
97 OPTIONS NOBOMFILE lrecl=32767;
98
99 /* set the header */
100 %mfs_httpheader(Content-type,application/json)
101
102 /* setup json. */
103 data _null_;file &fref encoding='utf-8' termstr=lf ;
104 put '{"SYSDATE" : "' "&SYSDATE" '"';
105 put ',"SYSTIME" : "' "&SYSTIME" '"';
106 run;
107
108%end;
109
110%else %if &action=ARR or &action=OBJ %then %do;
111 %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
112 /* functions in formats unsupported */
113 %put &sysmacroname: forcing missing back to NULL as feature not supported;
114 %let missing=NULL;
115 %end;
116 %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
117 ,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
118 )
119%end;
120%else %if &action=CLOSE %then %do;
121 %if %str(&workobs) > 0 %then %do;
122 /* if debug mode, send back first XX records of each work table also */
123 data;run;%let tempds=%scan(&syslast,2,.);
124 ods output Members=&tempds;
125 proc datasets library=WORK memtype=data;
126 %local wtcnt;%let wtcnt=0;
127 data _null_;
128 set &tempds;
129 if not (upcase(name) =:"DATA"); /* ignore temp datasets */
130 if not (upcase(name)=:"_DATA_");
131 i+1;
132 call symputx(cats('wt',i),name,'l');
133 call symputx('wtcnt',i,'l');
134 data _null_; file &fref mod encoding='utf-8' termstr=lf;
135 put ",""WORK"":{";
136 %do i=1 %to &wtcnt;
137 %let wt=&&wt&i;
138 data _null_; file &fref mod encoding='utf-8' termstr=lf;
139 dsid=open("WORK.&wt",'is');
140 nlobs=attrn(dsid,'NLOBS');
141 nvars=attrn(dsid,'NVARS');
142 rc=close(dsid);
143 if &i>1 then put ','@;
144 put " ""&wt"" : {";
145 put '"nlobs":' nlobs;
146 put ',"nvars":' nvars;
147 %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
148 ,maxobs=&workobs
149 )
150 data _null_; file &fref mod encoding='utf-8' termstr=lf;
151 put "}";
152 %end;
153 data _null_; file &fref mod encoding='utf-8' termstr=lf;
154 put "}";
155 run;
156 %end;
157 /* close off json */
158 data _null_;file &fref mod encoding='utf-8' termstr=lf lrecl=32767;
159 length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
160 put ",""_DEBUG"" : ""&_debug"" ";
161 _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
162 put ',"_PROGRAM" : ' _PROGRAM ;
163 autoexec=quote(urlencode(trim(getoption('autoexec'))));
164 put ',"AUTOEXEC" : ' autoexec;
165 put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
166 put ",""SYSCC"" : ""&syscc"" ";
167 put ",""SYSENCODING"" : ""&sysencoding"" ";
168 syserrortext=cats(symget('syserrortext'));
169 if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
170 syserrortext='"'!!trim(
171 prxchange('s/"/\\"/',-1, /* double quote */
172 prxchange('s/\x0A/\n/',-1, /* new line */
173 prxchange('s/\x0D/\r/',-1, /* carriage return */
174 prxchange('s/\x09/\\t/',-1, /* tab */
175 prxchange('s/\x00/\\u0000/',-1, /* NUL */
176 prxchange('s/\x0E/\\u000E/',-1, /* SS */
177 prxchange('s/\x0F/\\u000F/',-1, /* SF */
178 prxchange('s/\x01/\\u0001/',-1, /* SOH */
179 prxchange('s/\x02/\\u0002/',-1, /* STX */
180 prxchange('s/\x10/\\u0010/',-1, /* DLE */
181 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
182 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
183 prxchange('s/\\/\\\\/',-1,syserrortext)
184 )))))))))))))!!'"';
185 end;
186 else syserrortext=cats('"',syserrortext,'"');
187 put ',"SYSERRORTEXT" : ' syserrortext;
188 SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
189 put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
190 put ",""SYSHOSTNAME"" : ""&syshostname"" ";
191 put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
192 put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
193 SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
194 put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
195 put ",""SYSJOBID"" : ""&sysjobid"" ";
196 put ",""SYSSCPL"" : ""&sysscpl"" ";
197 put ",""SYSSITE"" : ""&syssite"" ";
198 put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
199 put ",""SYSUSERID"" : ""&sysuserid"" ";
200 sysvlong=quote(trim(symget('sysvlong')));
201 put ',"SYSVLONG" : ' sysvlong;
202 syswarningtext=cats(symget('syswarningtext'));
203 if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
204 syswarningtext='"'!!trim(
205 prxchange('s/"/\\"/',-1, /* double quote */
206 prxchange('s/\x0A/\n/',-1, /* new line */
207 prxchange('s/\x0D/\r/',-1, /* carriage return */
208 prxchange('s/\x09/\\t/',-1, /* tab */
209 prxchange('s/\x00/\\u0000/',-1, /* NUL */
210 prxchange('s/\x0E/\\u000E/',-1, /* SS */
211 prxchange('s/\x0F/\\u000F/',-1, /* SF */
212 prxchange('s/\x01/\\u0001/',-1, /* SOH */
213 prxchange('s/\x02/\\u0002/',-1, /* STX */
214 prxchange('s/\x10/\\u0010/',-1, /* DLE */
215 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
216 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
217 prxchange('s/\\/\\\\/',-1,syswarningtext)
218 )))))))))))))!!'"';
219 end;
220 else syswarningtext=cats('"',syswarningtext,'"');
221 put ',"SYSWARNINGTEXT" : ' syswarningtext;
222 put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
223 length memsize $32;
224 memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
225 memsize=quote(cats(memsize));
226 put ',"MEMSIZE" : ' memsize;
227 put "}" @;
228 run;
229%end;
230
231%mend ms_webout;