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 call symputx('input_statement',_infile_);
78 putlog "&&_webin_name&i input statement: " _infile_;
79 stop;
80 data &&_webin_name&i;
81 infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding='utf-8'
82 lrecl=32767;
83 input &input_statement;
84 %if %str(&_debug) ge 131 %then %do;
85 if _n_<20 then putlog _infile_;
86 %end;
87 run;
88 %let sasjs_tables=&sasjs_tables &&_webin_name&i;
89 %end;
90%end;
91
92%else %if &action=OPEN %then %do;
93 /* fix encoding and ensure enough lrecl */
94 OPTIONS NOBOMFILE lrecl=32767;
95
96 /* set the header */
97 %mfs_httpheader(Content-type,application/json)
98
99 /* setup json. */
100 data _null_;file &fref encoding='utf-8' termstr=lf ;
101 put '{"SYSDATE" : "' "&SYSDATE" '"';
102 put ',"SYSTIME" : "' "&SYSTIME" '"';
103 run;
104
105%end;
106
107%else %if &action=ARR or &action=OBJ %then %do;
108 %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
109 /* functions in formats unsupported */
110 %put &sysmacroname: forcing missing back to NULL as feature not supported;
111 %let missing=NULL;
112 %end;
113 %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
114 ,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
115 )
116%end;
117%else %if &action=CLOSE %then %do;
118 %if %str(&workobs) > 0 %then %do;
119 /* if debug mode, send back first XX records of each work table also */
120 data;run;%let tempds=%scan(&syslast,2,.);
121 ods output Members=&tempds;
122 proc datasets library=WORK memtype=data;
123 %local wtcnt;%let wtcnt=0;
124 data _null_;
125 set &tempds;
126 if not (upcase(name) =:"DATA"); /* ignore temp datasets */
127 if not (upcase(name)=:"_DATA_");
128 i+1;
129 call symputx(cats('wt',i),name,'l');
130 call symputx('wtcnt',i,'l');
131 data _null_; file &fref mod encoding='utf-8' termstr=lf;
132 put ",""WORK"":{";
133 %do i=1 %to &wtcnt;
134 %let wt=&&wt&i;
135 data _null_; file &fref mod encoding='utf-8' termstr=lf;
136 dsid=open("WORK.&wt",'is');
137 nlobs=attrn(dsid,'NLOBS');
138 nvars=attrn(dsid,'NVARS');
139 rc=close(dsid);
140 if &i>1 then put ','@;
141 put " ""&wt"" : {";
142 put '"nlobs":' nlobs;
143 put ',"nvars":' nvars;
144 %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
145 ,maxobs=&workobs
146 )
147 data _null_; file &fref mod encoding='utf-8' termstr=lf;
148 put "}";
149 %end;
150 data _null_; file &fref mod encoding='utf-8' termstr=lf;
151 put "}";
152 run;
153 %end;
154 /* close off json */
155 data _null_;file &fref mod encoding='utf-8' termstr=lf lrecl=32767;
156 length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
157 put ",""_DEBUG"" : ""&_debug"" ";
158 _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
159 put ',"_PROGRAM" : ' _PROGRAM ;
160 autoexec=quote(urlencode(trim(getoption('autoexec'))));
161 put ',"AUTOEXEC" : ' autoexec;
162 put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
163 put ",""SYSCC"" : ""&syscc"" ";
164 put ",""SYSENCODING"" : ""&sysencoding"" ";
165 syserrortext=cats(symget('syserrortext'));
166 if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
167 syserrortext='"'!!trim(
168 prxchange('s/"/\\"/',-1, /* double quote */
169 prxchange('s/\x0A/\n/',-1, /* new line */
170 prxchange('s/\x0D/\r/',-1, /* carriage return */
171 prxchange('s/\x09/\\t/',-1, /* tab */
172 prxchange('s/\x00/\\u0000/',-1, /* NUL */
173 prxchange('s/\x0E/\\u000E/',-1, /* SS */
174 prxchange('s/\x0F/\\u000F/',-1, /* SF */
175 prxchange('s/\x01/\\u0001/',-1, /* SOH */
176 prxchange('s/\x02/\\u0002/',-1, /* STX */
177 prxchange('s/\x10/\\u0010/',-1, /* DLE */
178 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
179 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
180 prxchange('s/\\/\\\\/',-1,syserrortext)
181 )))))))))))))!!'"';
182 end;
183 else syserrortext=cats('"',syserrortext,'"');
184 put ',"SYSERRORTEXT" : ' syserrortext;
185 SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
186 put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
187 put ",""SYSHOSTNAME"" : ""&syshostname"" ";
188 put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
189 put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
190 SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
191 put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
192 put ",""SYSJOBID"" : ""&sysjobid"" ";
193 put ",""SYSSCPL"" : ""&sysscpl"" ";
194 put ",""SYSSITE"" : ""&syssite"" ";
195 put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
196 put ",""SYSUSERID"" : ""&sysuserid"" ";
197 sysvlong=quote(trim(symget('sysvlong')));
198 put ',"SYSVLONG" : ' sysvlong;
199 syswarningtext=cats(symget('syswarningtext'));
200 if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
201 syswarningtext='"'!!trim(
202 prxchange('s/"/\\"/',-1, /* double quote */
203 prxchange('s/\x0A/\n/',-1, /* new line */
204 prxchange('s/\x0D/\r/',-1, /* carriage return */
205 prxchange('s/\x09/\\t/',-1, /* tab */
206 prxchange('s/\x00/\\u0000/',-1, /* NUL */
207 prxchange('s/\x0E/\\u000E/',-1, /* SS */
208 prxchange('s/\x0F/\\u000F/',-1, /* SF */
209 prxchange('s/\x01/\\u0001/',-1, /* SOH */
210 prxchange('s/\x02/\\u0002/',-1, /* STX */
211 prxchange('s/\x10/\\u0010/',-1, /* DLE */
212 prxchange('s/\x11/\\u0011/',-1, /* DC1 */
213 prxchange('s/\x1A/\\u001A/',-1, /* SUB */
214 prxchange('s/\\/\\\\/',-1,syswarningtext)
215 )))))))))))))!!'"';
216 end;
217 else syswarningtext=cats('"',syswarningtext,'"');
218 put ',"SYSWARNINGTEXT" : ' syswarningtext;
219 put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
220 length memsize $32;
221 memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
222 memsize=quote(cats(memsize));
223 put ',"MEMSIZE" : ' memsize;
224 put "}" @;
225 run;
226%end;
227
228%mend ms_webout;