Production Ready Macros for SAS Application Developers
https://github.com/sasjs/core
mv_webout.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Send data to/from the SAS Viya Job Execution Service
4 @details This macro should be added to the start of each Job Execution
5 Service, **immediately** followed by a call to:
6
7 %mv_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 %mv_webout(OPEN)
18 %mv_webout(ARR,some) * Array format, fast, suitable for large tables ;
19 %mv_webout(OBJ,datasets) * Object format, easier to work with ;
20 %mv_webout(CLOSE)
21
22
23 @param action Either OPEN, ARR, OBJ or CLOSE
24 @param ds The dataset to send back to the frontend
25 @param _webout= fileref for returning the json
26 @param fref=(_mvwtemp) Temp fileref to which to write the output
27 @param dslabel= value to use instead of the real name for sending to JSON
28 @param fmt=(Y) change to N to strip formats from output
29 @param stream=(Y) Change to N if not streaming to _webout
30
31 <h4> SAS Macros </h4>
32 @li mp_jsonout.sas
33 @li mf_getuser.sas
34
35 @version Viya 3.3
36 @author Allan Bowe, source: https://github.com/sasjs/core
37
38**/
39%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y);
40%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
41 sasjs_tables SYS_JES_JOB_URI;
42%if %index("&_debug",log) %then %let _debug=131;
43
44%local i tempds;
45%let action=%upcase(&action);
46
47%if &action=FETCH %then %do;
48 %if %upcase(&_omittextlog)=FALSE or %str(&_debug) ge 131 %then %do;
49 options mprint notes mprintnest;
50 %end;
51
52 %if not %symexist(_webin_fileuri1) %then %do;
53 %let _webin_file_count=%eval(&_webin_file_count+0);
54 %let _webin_fileuri1=&_webin_fileuri;
55 %let _webin_name1=&_webin_name;
56 %end;
57
58 /* if the sasjs_tables param is passed, we expect param based upload */
59 %if %length(&sasjs_tables.XX)>2 %then %do;
60 filename _sasjs "%sysfunc(pathname(work))/sasjs.lua";
61 data _null_;
62 file _sasjs;
63 put 's=sas.symget("sasjs_tables")';
64 put 'if(s:sub(1,7) == "%nrstr(")';
65 put 'then';
66 put ' tablist=s:sub(8,s:len()-1)';
67 put 'else';
68 put ' tablist=s';
69 put 'end';
70 put 'for i = 1,sas.countw(tablist) ';
71 put 'do ';
72 put ' tab=sas.scan(tablist,i)';
73 put ' sasdata=""';
74 put ' if (sas.symexist("sasjs"..i.."data0")==0)';
75 put ' then';
76 /* TODO - condense this logic */
77 put ' s=sas.symget("sasjs"..i.."data")';
78 put ' if(s:sub(1,7) == "%nrstr(")';
79 put ' then';
80 put ' sasdata=s:sub(8,s:len()-1)';
81 put ' else';
82 put ' sasdata=s';
83 put ' end';
84 put ' else';
85 put ' for d = 1, sas.symget("sasjs"..i.."data0")';
86 put ' do';
87 put ' s=sas.symget("sasjs"..i.."data"..d)';
88 put ' if(s:sub(1,7) == "%nrstr(")';
89 put ' then';
90 put ' sasdata=sasdata..s:sub(8,s:len()-1)';
91 put ' else';
92 put ' sasdata=sasdata..s';
93 put ' end';
94 put ' end';
95 put ' end';
96 put ' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")';
97 put ' io.output(file)';
98 put ' io.write(sasdata)';
99 put ' io.close(file)';
100 put 'end';
101 run;
102 %inc _sasjs;
103
104 /* now read in the data */
105 %do i=1 %to %sysfunc(countw(&sasjs_tables));
106 %local table; %let table=%scan(&sasjs_tables,&i);
107 data _null_;
108 infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
109 input;
110 if _n_=1 then call symputx('input_statement',_infile_);
111 list;
112 data &table;
113 infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
114 termstr=crlf;
115 input &input_statement;
116 run;
117 %end;
118 %end;
119 %else %do i=1 %to &_webin_file_count;
120 /* read in any files that are sent */
121 /* this part needs refactoring for wide files */
122 filename indata filesrvc "&&_webin_fileuri&i" lrecl=999999;
123 data _null_;
124 infile indata termstr=crlf lrecl=32767;
125 input;
126 if _n_=1 then call symputx('input_statement',_infile_);
127 %if %str(&_debug) ge 131 %then %do;
128 if _n_<20 then putlog _infile_;
129 else stop;
130 %end;
131 %else %do;
132 stop;
133 %end;
134 run;
135 data &&_webin_name&i;
136 infile indata firstobs=2 dsd termstr=crlf ;
137 input &input_statement;
138 run;
139 %let sasjs_tables=&sasjs_tables &&_webin_name&i;
140 %end;
141%end;
142%else %if &action=OPEN %then %do;
143 /* setup webout */
144 OPTIONS NOBOMFILE;
145 %if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
146 filename _webout temp lrecl=999999 mod;
147 %end;
148 %else %do;
149 filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
150 name="_webout.json" lrecl=999999 mod;
151 %end;
152
153 /* setup temp ref */
154 %if %upcase(&fref) ne _WEBOUT %then %do;
155 filename &fref temp lrecl=999999 permission='A::u::rwx,A::g::rw-,A::o::---'
156 mod;
157 %end;
158
159 /* setup json */
160 data _null_;file &fref;
161 put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
162 run;
163%end;
164%else %if &action=ARR or &action=OBJ %then %do;
165 %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
166 ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug)
167 )
168%end;
169%else %if &action=CLOSE %then %do;
170 %if %str(&_debug) ge 131 %then %do;
171 /* send back first 10 records of each work table for debugging */
172 options obs=10;
173 data;run;%let tempds=%scan(&syslast,2,.);
174 ods output Members=&tempds;
175 proc datasets library=WORK memtype=data;
176 %local wtcnt;%let wtcnt=0;
177 data _null_;
178 set &tempds;
179 if not (upcase(name) =:"DATA"); /* ignore temp datasets */
180 i+1;
181 call symputx('wt'!!left(i),name);
182 call symputx('wtcnt',i);
183 data _null_; file &fref mod; put ",""WORK"":{";
184 %do i=1 %to &wtcnt;
185 %let wt=&&wt&i;
186 proc contents noprint data=&wt
187 out=_data_ (keep=name type length format:);
188 run;%let tempds=%scan(&syslast,2,.);
189 data _null_; file &fref mod;
190 dsid=open("WORK.&wt",'is');
191 nlobs=attrn(dsid,'NLOBS');
192 nvars=attrn(dsid,'NVARS');
193 rc=close(dsid);
194 if &i>1 then put ','@;
195 put " ""&wt"" : {";
196 put '"nlobs":' nlobs;
197 put ',"nvars":' nvars;
198 %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
199 %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
200 data _null_; file &fref mod;put "}";
201 %end;
202 data _null_; file &fref mod;put "}";run;
203 %end;
204
205 /* close off json */
206 data _null_;file &fref mod;
207 _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
208 put ",""SYSUSERID"" : ""&sysuserid"" ";
209 put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
210 SYS_JES_JOB_URI=quote(trim(resolve(symget('SYS_JES_JOB_URI'))));
211 put ',"SYS_JES_JOB_URI" : ' SYS_JES_JOB_URI ;
212 put ",""SYSJOBID"" : ""&sysjobid"" ";
213 put ",""_DEBUG"" : ""&_debug"" ";
214 put ',"_PROGRAM" : ' _PROGRAM ;
215 put ",""SYSCC"" : ""&syscc"" ";
216 put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
217 put ",""SYSHOSTNAME"" : ""&syshostname"" ";
218 put ",""SYSSCPL"" : ""&sysscpl"" ";
219 put ",""SYSSITE"" : ""&syssite"" ";
220 sysvlong=quote(trim(symget('sysvlong')));
221 put ',"SYSVLONG" : ' sysvlong;
222 put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
223 put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
224 put "}";
225
226 %if %upcase(&fref) ne _WEBOUT and &stream=Y %then %do;
227 data _null_; rc=fcopy("&fref","_webout");run;
228 %end;
229
230%end;
231
232%mend mv_webout;