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