getdata.sas
Go to the documentation of this file.
1 /**
2  @file getdata.sas
3  @brief Returns a dataset to the editor front end
4  @details
5 
6  <h4> Service Inputs </h4>
7 
8  <h5> SASCONTROLTABLE </h5>
9  |LIBDS:$41.|FILTER_RK:$5.|
10  |---|---|
11  |DC258467.MPE_X_TEST|-1|
12 
13  <h4> Service Outputs </h4>
14  <h5> sasdata </h5>
15  <h5> sasparams </h5>
16  Contains info on the request. One row is returned.
17  @li CLS_FLG - set to 0 if there are no CLS rules (everything editable)
18  else set to 1 (CLS rules exist)
19  @li ISMAP - set to 1 if the target DS is an excel map target, else 0
20 
21  <h5> approvers </h5>
22  <h5> dqrules </h5>
23  <h5> dqdata </h5>
24  <h5> cols </h5>
25  Contains column level attributes.
26  @li NAME - column name
27  @li VARNUM - variable position. Source: https://core.sasjs.io/mp__getcols_8sas.html
28  @li LABEL - variable label. Source: https://core.sasjs.io/mp__getcols_8sas.html
29  @li FMTNAME - derived format name. Source: https://core.sasjs.io/mp__getcols_8sas.html
30  @li DDTYPE - derived dropdown type. Source: https://core.sasjs.io/mp__getcols_8sas.html
31  @li CLS_RULE - values include:
32  - EDIT - the column is editable
33  - READ - the column should be readonly
34  - HIDE - the column should be hidden
35  @li memlabel
36  @li desc- augmented with MPE_DATADICTIONARY if exists, else label
37  @li longdesc - from MPE_DATADICTIONARY
38 
39 
40  <h5> maxvarlengths </h5>
41  <h5> xl_rules </h5>
42  <h5> query </h5>
43 
44  <h5> versions </h5>
45  history of DC versions for this particular table
46 
47 
48  <h4> SAS Macros </h4>
49  @li dc_assignlib.sas
50  @li dc_getgroupmembers.sas
51  @li mf_existvar.sas
52  @li mf_getattrn.sas
53  @li mf_getvarlist.sas
54  @li mf_existds.sas
55  @li mf_getquotedstr.sas
56  @li mf_getuser.sas
57  @li mf_nobs.sas
58  @li mf_verifymacvars.sas
59  @li mf_wordsinstr1butnotstr2.sas
60  @li mp_abort.sas
61  @li mp_cntlout.sas
62  @li mp_getcols.sas
63  @li mp_getmaxvarlengths.sas
64  @li mp_validatecol.sas
65  @li mpe_accesscheck.sas
66  @li mpe_columnlevelsecurity.sas
67  @li mpe_dsmeta.sas
68  @li mpe_getlabels.sas
69  @li mpe_getversions.sas
70  @li mpe_filtermaster.sas
71  @li mpe_runhook.sas
72 
73  @version 9.2
74  @author 4GL Apps Ltd
75  @copyright 4GL Apps Ltd. This code may only be used within Data Controller
76  and may not be re-distributed or re-sold without the express permission of
77  4GL Apps Ltd.
78 
79 **/
80 
81 %mpeinit()
82 
83 /**
84  * Validate inputs
85  */
86 data work.intest;
87  length filter_rk 8;
88  set work.SASCONTROLTABLE;
89 
90  /* validate filter_rk */
91  if filter_rk le 0 then filter_rk=-1;
92 
93  call symputx('orig_libds',upcase(libds));
94 
95  is_fmt=0;
96  if substr(cats(reverse(libds)),1,3)=:'CF-' then do;
97  libds=scan(libds,1,'-');
98  putlog "Format Catalog Captured";
99  is_fmt=1;
100  libds='work.fmtextract';
101  call symputx('libds',libds);
102  end;
103  call symputx('is_fmt',is_fmt);
104  putlog (_all_)(=);
105 
106  /* validate libds */
107  %mp_validatecol(LIBDS,LIBDS,is_libds)
108 
109  if is_libds=0 then do;
110  putlog 'ERR' 'OR: Invalid libds:' libds;
111  stop;
112  end;
113  else do;
114  call symputx('filter_rk',filter_rk);
115  call symputx('libds',libds);
116  end;
117  output;
118  stop;
119 run;
120 
121 %mp_abort(iftrue= (%mf_nobs(work.intest)=0)
122  ,mac=&_program
123  ,msg=%str(Some err with service inputs)
124 )
125 
126 %mp_abort(
127  iftrue=(%mf_verifymacvars(libds filter_rk)=0)
128  ,mac=&_program
129  ,msg=%str(Missing: libds filter_rk)
130 )
131 
132 /* export format catalog */
133 %mp_cntlout(
134  iftrue=(&is_fmt=1)
135  ,libcat=&orig_libds
136  ,fmtlist=0
137  ,cntlout=work.fmtextract
138 )
139 
140 /* stream back meta info, further calls will return col metadata and actual data
141 */
142 %let libref=%upcase(%scan(&libds,1,.));
143 %let dsn=%upcase(%scan(&libds,2,.));
144 %dc_assignlib(WRITE,&libref)
145 
146 /**
147  * First check user has access permission to edit the table
148  */
149 %put checking access;
150 %let user=%mf_getuser();
151 %mpe_accesscheck(&orig_libds,outds=mw_auth,user=&user,access_level=EDIT)
152 
153 
154 %mp_abort(iftrue= (%mf_getattrn(work.mw_auth,NLOBS)=0)
155  ,mac=mpestp_getdata.sas
156  ,msg=&user is not authorised to edit &orig_libds %trim(
157  )in the &mpelib..MPE_SECURITY table
158 )
159 
160 %mp_abort(iftrue= ( %mf_existds(libds=&libds) ne 1)
161  ,mac=mpestp_getdata.sas
162  ,msg=dataset &libds does not exist!!
163 )
164 
165 %mp_abort(iftrue= (&syscc ne 0)
166  ,mac=&_program..sas
167  ,msg=%str(syscc=&syscc at line 60 )
168 )
169 
170 
171 %global loadtype var_txfrom var_txto var_processed filter_text pk coltype
172  sortpk;
173 
174 %put getting table attributes;
175 proc sql noprint;
176 select upcase(loadtype)
177  ,var_txfrom,var_txto
178  ,var_busfrom,var_busto
179  ,var_processed,rk_underlying,buskey
180  ,coalesce(rk_underlying,buskey)
181  ,pre_edit_hook
182  ,case when missing(rk_underlying) then buskey else rk_underlying end
183  into: loadtype,:var_txfrom,:var_txto
184  ,:var_busfrom ,:var_busto
185  ,:var_processed,:rk_underlying,:buskey, :sortPK, :pre_edit_hook,:pk
186  from &mpelib..mpe_tables
187  where &dc_dttmtfmt. lt TX_TO
188  and upcase(dsn)="%scan(&orig_libds,2,.)"
189  and upcase(libref)="%scan(&orig_libds,1,.)";
190 
191 %put preparing filter query:;
192 %mpe_filtermaster(EDIT,&orig_libds,
193  dclib=&mpelib,
194  filter_rk=&filter_rk,
195  outref=filtref,
196  outds=work.query
197 )
198 
199 %macro mpestp_getdata();
200  %if not %symexist(DC_MAXOBS_WEBEDIT) %then %do;
201  %put NOTE:;%put NOTE- DC_MAXOBS_WEBEDIT not found!;
202  %put NOTE- Please add to &mpelib..MPE_CONFIG table;
203  %put NOTE-;%put NOTE-;
204  %global DC_MAXOBS_WEBEDIT;
205  %let DC_MAXOBS_WEBEDIT=500;
206  %end;
207  /* for tables which use RKs/SKs then we just expose the business key to
208  users - this lets uploads be sent to multiple environments (with
209  potentially different RK/SK values for the same business key).
210  Note that the config table has the RK column in the buskey field in
211  this scenario. */
212  %if %length(&rk_underlying)>0 %then %let drop_rk=&buskey;
213  %else %let drop_rk=;
214 
215  /* always remove the PROCESSED_DTTM column, if it exists */
216  %if %length(&var_processed)=0 %then %do;
217  %if %mf_existvar(&libds,PROCESSED_DTTM)>0 %then
218  %let var_processed=PROCESSED_DTTM;
219  %end;
220 
221  /**
222  * Now get the slice of the actual table
223  */
224  options obs=10000;
225 
226  %if &loadtype=BITEMPORAL %then %do;
227  data out (drop=&var_txfrom &var_txto &var_processed &drop_rk );
228  _____DELETE__THIS__RECORD_____="No";
229  set &libds;
230  where %inc filtref;;
231  run;
232  proc sort data=out;
233  by &pk &var_busfrom;
234  run;
235  data out;
236  set out;
237  by &pk &var_busfrom;
238  if last.%scan(&pk,-1);
239  run;
240  %end;
241  %else %do;
242  data out (drop=&var_txfrom &var_txto &var_processed &drop_rk);
243  _____DELETE__THIS__RECORD_____="No";
244  set &libds;
245  where %inc filtref;;
246  run;
247  %end;
248  options obs=max;
249  %mp_abort(iftrue= (&syscc ne 0)
250  ,mac=&_program
251  ,msg=%str(Issue with filtering (line 165) )
252  )
253 
254  options obs=&DC_MAXOBS_WEBEDIT;
255  %let sortpk=%sysfunc(coalescec(&sortpk &var_busfrom,_ALL_));
256  proc sort data=work.out; by &sortPK; run;
257  options obs=max;
258 
259  %mpe_runhook(PRE_EDIT_HOOK)
260 
261  %let obscnt=%mf_getattrn(work.out,NLOBS);
262  %mp_abort(iftrue=(&obscnt>&DC_MAXOBS_WEBEDIT)
263  ,mac=&_program
264  ,msg=Table is too big (&obscnt rows) - please filter and try again!
265  )
266 
267 
268  /* order delete var and pk fields at start of table */
269  %let sourcevars=%mf_wordsInStr1ButNotStr2(
270  Str1=%mf_getvarlist(work.out)
271  ,Str2= _____DELETE__THIS__RECORD_____ &pk
272  );
273  %put sourcevars=&sourcevars;
274  data outdata;
275  /* delete & pk fields come first */
276  attrib _____DELETE__THIS__RECORD_____ &pk label='';
277  /* keep remaining variable order */
278  %if %length(&sourcevars)>0 %then %do;
279  attrib &sourcevars label='';
280  %end;
281  _____DELETE__THIS__RECORD_____="No ";
282  %if %mf_nobs(work.out)=0 %then %do;
283  /* send empty row if empty table to help with hot rendering */
284  output;
285  %end;
286  set work.out ;
287  run;
288 
289 
290 
291  /* get list of variables and their formats */
292  proc contents noprint data=outdata
293  out=vars(keep=name type length varnum format: label);
294  run;
295 
296  proc sort;
297  by varnum;
298  run;
299 
300  data vars3(keep=name type length format label pk varnum ctrloptions formatd);
301  set vars(rename=(format=format2 type=type2));
302  name=upcase(name);
303  /* not interested in transaction or processing dates
304  (append table must be supplied without them) */
305  if name not in ("&VAR_TXFROM","&VAR_TXTO","&VAR_PROCESSED");
306  if type2=2 or type2=6 then do;
307  length format $49.;
308  if format2='' then format=cats('$',length,'.');
309  else format=cats(format2,formatl,'.');
310  type='char';
311  end;
312  else do;
313  if format2='' then format=cats(length,'.');
314  else if upcase(format2)='DATETIME' and formatl=0 then format='DATETIME.';
315  else format=cats(format2,formatl,'.',formatd);
316  type='num';
317  end;
318 
319  if name in ('',%upcase(%mf_getQuotedStr(&pk,dlm=%str(,),quote=S)))
320  then PK='YES';
321 
322  length ctrlOptions $500;
323  if name="_____DELETE__THIS__RECORD_____" then ctrlOptions='["No","Yes"]';
324  else ctrlOptions='';
325  run;
326  %mp_abort(iftrue= (&syscc ne 0)
327  ,mac=&_program..sas
328  ,msg=%str(syscc=&syscc at 242 (vars3 step) in &_program \n
329  %superq(syserrortext)
330  )
331  )
332 
333  %global jsdttmvars jsdtvars jstmvars;
334  data _null_;
335  set vars3 end=last;
336  if _n_>1 then comma=',';
337  length coltype $500.;
338  format=upcase(format);
339  coltype=cats(comma,'{"data":"',name,'"');
340  if ctrlOptions ne '' then
341  colType=cats(coltype,',"type":"dropdown","source":',ctrlOptions,"}");
342  else if type='num' then do;
343  if format=:'DATETIME' or format=:'E8601DT' then do;
344  colType=cats(coltype
345  ,',"type":"date","dateFormat":"YYYY-MM-DD HH:mm:ss"'
346  ,',"correctFormat":"true"}');
347  /* build var list to reformat datetimes in javascript format */
348  call symput('jsdttmvars',symget('jsdttmvars')!!' '!!name);
349  end;
350  else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
351  or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
352  or format=:'MONYY'
353  then do;
354  /* see bottom of file for more date formats!! */
355  /* also when updating, update stagedata.sas and mp_getcols.sas
356  and mpe_loader.sas */
357  colType=cats(coltype,',"type":"date","dateFormat":"YYYY-MM-DD"'
358  /*colType=cats(coltype,',"type":"date","dateFormat":"MM/DD/YYYY"'*/
359  ,',"correctFormat":"true"}');
360  /* build var list to reformat as javascript dates */
361  call symput('jsdtvars',symget('jsdtvars')!!' '!!name);
362  end;
363  else if format=:'TIME' or format=:'HHMM' then do;
364  colType=cats(coltype,',"type":"time","timeFormat":"HH:mm:ss"'
365  ,',"correctFormat":"true"}');
366  /* build var list to reformat as javascript times */
367  call symput('jstmvars',symget('jstmvars')!!' '!!name);
368  end;
369  else do;
370  /* is standard numeric but need to ascertain precision */
371  retain base '000000000000000000';
372  if formatd>0 then numFormat=cats('.',substr(base,1,formatd));
373  colType=cats(coltype,',"type":"numeric","format":"0',numFormat,'"}');
374  end;
375  end;
376  else colType=cats(coltype,'}');
377  length concatcoltype $32767;
378  retain concatcoltype;
379  concatcoltype=cats(concatcoltype,coltype);
380  if last then call symputx('colType',strip(concatcoltype),'g');
381  putlog (_all_)(=);
382  run;
383 
384  %mp_abort(iftrue= (&syscc ne 0)
385  ,mac=&_program..sas
386  ,msg=%str(syscc=&syscc at 283 (null step) in &_program)
387  )
388 
389  PROC FORMAT;
390  picture yymmddThhmmss (default=28) other='%0Y-%0m-%0d %0H:%0M:%0s'
391  (datatype=datetime);
392  picture JSyymmdd other='%0Y-%0m-%0d' (datatype=date);
393  picture JShhmmss (default=16) other='%0H:%0M:%0s' (datatype=time);
394  RUN;
395  /* before we send the data, need to rebuild all date & datetime vars as char*/
396  %let finalvars=%mf_getvarlist(work.outdata);
397  data sasdata;
398  /* set formats & col order ahead of rename+import */
399  informat &finalvars ;
400  /* read dataset and rename date / datetime vars as necessary */
401  set outdata
402  %if %length(&jsdttmvars&jsdtvars&jstmvars)>0 %then %do;
403  (rename=(
404  %local dtvarnum dtvar tmvar;
405  /* temp datetime vars end in _____ */
406  %do dtvarnum=1 %to %sysfunc(countw(&jsdttmvars,%str( )));
407  %let dtvar=%scan(&jsdttmvars ,&dtvarnum);
408  &dtvar=_____&dtvarnum._____
409  %end;
410  /* temp date vars do not end in _____ */
411  %do dtvarnum=1 %to %sysfunc(countw(&jsdtvars,%str( )));
412  %let dtvar=%scan( &jsdtvars,&dtvarnum);
413  &dtvar=_____&dtvarnum
414  %end;
415  /* temp time vars end in ___tm */
416  %do tmvarnum=1 %to %sysfunc(countw(&jstmvars,%str( )));
417  %let tmvar=%scan( &jstmvars,&tmvarnum);
418  &tmvar=_____&tmvarnum.___tm
419  %end;
420  ))
421  %end;
422  ;
423  %if %length(&jsdttmvars)>0 %then %do ;
424  %do dtvarnum=1 %to %sysfunc(countw(&jsdttmvars,%str( )));
425  %let dtvar=%scan(&jsdttmvars,&dtvarnum);
426  &dtvar=cats(put(_____&dtvarnum._____,yymmddThhmmss28.));
427  if &dtvar="ERROR" then call missing(&dtvar);
428  drop _____&dtvarnum._____;
429  %end;
430  %end;
431  %if %length(&jsdtvars)>0 %then %do;
432  %do dtvarnum=1 %to %sysfunc(countw(&jsdtvars,%str( )));
433  %let dtvar=%scan(&jsdtvars,&dtvarnum);
434  &dtvar=cats(put(_____&dtvarnum,JSyymmdd.));
435  if &dtvar="ERROR" then call missing(&dtvar);
436  drop _____&dtvarnum;
437  %end;
438  %end;
439  %if %length(&jstmvars)>0 %then %do;
440  %do tmvarnum=1 %to %sysfunc(countw(&jstmvars,%str( )));
441  %let tmvar=%scan(&jstmvars,&tmvarnum);
442  &tmvar=cats(put(_____&tmvarnum.___tm,JShhmmss14.));
443  if &tmvar="ERROR" then call missing(&tmvar);
444  drop _____&tmvarnum.___tm;
445  %end;
446  %end;
447  output;
448  run;
449 
450  /* get the relevant approvers for the drop down */
451  %put getting approvers;
452  %local sas_groups sas_i sas_group;
453  proc sql noprint;
454  select distinct sas_Group into: sas_groups separated by "|"
455  from &mpelib..mpe_security
456  where libref="%scan(&orig_libds,1,.)"
457  and dsn="%scan(&orig_libds,2,.)"
458  and access_level='APPROVE'
459  and &dc_dttmtfmt. lt TX_TO;
460 
461  %if %length(&sas_groups)=0 %then %do;
462  %dc_getgroupmembers(&dc_admin_group,outds=work.access1)
463  %end;
464  %else %do sas_i=1 %to %sysfunc(countw(&sas_groups,%str(|)));
465  %let sas_group=%scan(&sas_Groups,&sas_i,%str(|));
466  %dc_getgroupmembers(&sas_group,outds=work.temp&sas_i)
467  proc append base=work.access1 data=work.temp&sas_i;run;
468  %end;
469 
470 %mend mpestp_getdata;
471 
472 %mpestp_getdata()
473 
474 %mp_abort(mode=INCLUDE)
475 
476 /* extract column level security rules */
477 %mpe_columnlevelsecurity(%scan(&libds,1,.),%scan(&libds,2,.),work.sasdata
478  ,mode=EDIT
479  ,clsds=&mpelib..mpe_column_level_security
480  ,groupds=work.groups /* was created in mpe_filtermaster */
481  ,outds=work.sasdata1
482  ,outmeta=work.cls_rules
483 )
484 
485 /* get labels */
486 %mpe_getlabels(COLUMNS,sasdata1,outds=spec)
487 %mp_abort(iftrue= (&syscc ne 0)
488  ,mac=&_program
489  ,msg=%str(syscc=&syscc extracting spec info)
490 )
491 
492 /* extract col info */
493 %mp_getcols(&libds, outds=cols1)
494 
495 /* join with cls rules */
496 proc sql;
497 create table work.cols as
498  select a.NAME
499  ,a.VARNUM
500  ,a.LABEL
501  ,a.FMTNAME
502  ,a.DDTYPE
503  ,case b.cls_hide
504  when 1 then 'HIDE'
505  when 0 then 'EDIT'
506  else 'READ' end as CLS_RULE
507  ,c.memlabel
508  ,c.desc
509  ,c.longdesc
510  from work.cols1 a
511  left join work.cls_rules b
512  on a.NAME=b.CLS_VARIABLE_NM
513  left join work.spec c
514  on a.NAME=c.NAME;
515 
516 proc sql;
517 create table approvers as select distinct membername as personname
518  ,membername as email, membername as userid
519  from work.access1;
520 /*
521 create table access3 as select b.userid,b.email
522  from access2 a
523  ,support.users b
524  where a.personname=b.userid
525  and a.personname ne "%mf_getuser()"
526  and %sysfunc(datetime()) lt b.tx_to_dttm
527  order by 1;
528 */
529 data _null_;
530  infile filtref end=eof;
531  input;
532  length filter_text $32767;
533  retain filter_text;
534  filter_text=catx(' ',filter_text,_infile_);
535  if eof then do;
536  if cats(filter_text)='1=1' then filter_text='';
537  call symputx('filter_text',filter_text);
538  end;
539 run;
540 
541 %put params;
542 %let ismap=0;
543 proc sql noprint;
544 select count(*) into: ismap from &mpelib..mpe_xlmap_info
545  where XLMAP_TARGETLIBDS="&orig_libds" and &dc_dttmtfmt. le TX_TO;
546 
547 data sasparams;
548  length colHeaders $20000 filter_text $32767;
549  colHeaders=cats(upcase("%mf_getvarlist(sasdata1,dlm=%str(,))"));
550  pkCnt=countw("&pk");
551  pk="&pk";
552  dtvars=compbl("&jsdtvars");
553  dttmvars=compbl("&jsdttmvars");
554  tmvars=compbl("&jstmvars");
555  length coltype $32000;
556  coltype=symget('coltype');
557  loadtype=symget('loadtype');
558  if trim(symget('rk_underlying')) ne '' then rk_flag=1;
559  else rk_flag=0;
560  filter_text=symget('filter_text');
561  if %mf_nobs(work.cls_rules)=0 then cls_flag=0;
562  else cls_flag=1;
563  put (_all_)(=);
564  if "&orig_libds"="&mpelib..MPE_XLMAP_DATA" or &ismap ne 0 then ismap=1;
565  else ismap=0;
566 run;
567 
568 
569 /* Extract validation DQ Rules */
570 proc sort data=&mpelib..mpe_validations
571  (where=(&dc_dttmtfmt. le TX_TO
572  and BASE_LIB="%scan(&orig_libds,1,.)" and BASE_DS="%scan(&orig_libds,2,.)"
573  and rule_active=1))
574  out=dqrules (keep=base_col rule_type rule_value);
575  by base_col rule_type rule_value;
576 run;
577 
578 /* merge with NOTNULL constraints in the physical table */
579 proc sql;
580 create table _data_ as
581  select * from dqrules
582 union
583  select upcase(name) as base_col
584  ,'NOTNULL' as rule_type
585  ,'' as rule_value
586  from dictionary.columns
587  where upcase(libname)="%scan(&orig_libds,1,.)"
588  and upcase(memname)="%scan(&orig_libds,2,.)"
589  and upcase(name) in (select name from vars3)
590  and notnull='yes'
591  order by 1,2,3;
592 data dqrules;
593  set &syslast;
594  by base_col rule_type rule_value;
595  if last.rule_type;
596  if rule_type in ('HARDSELECT','SOFTSELECT') and countw(rule_value)=3 then
597  do;
598  retain x 0; x+1;
599  call symputx(cats('source',x),rule_value);
600  %let sourcecnt=0;
601  call symputx('sourcecnt',x);
602  call symputx(cats('base_col',x),base_col);
603  end;
604 run;
605 
606 proc sql;
607 create table dqdata as
608  select distinct base_column as base_col length=32
609  ,upcase(base_column) as rule_value length=74 /* deprecated */
610  ,selectbox_value as rule_data length=1000
611  ,selectbox_order
612  from &mpelib..mpe_selectbox
613  where &dc_dttmtfmt. lt ver_to_dttm
614  and select_lib="%scan(&orig_libds,1,.)"
615  and select_ds="%scan(&orig_libds,2,.)";
616 
617 %mp_abort(iftrue= (&syscc ne 0)
618  ,mac=&_program
619  ,msg=%str(syscc=&syscc during DQ rule validation)
620 )
621 
622 /* extract selectbox data */
623 %macro dq_selects();
624  %local x source lib ds col;
625  %do x=1 %to &sourcecnt;
626  %let source=&&source&x;
627  %let lib=%scan(&source,1,.);
628  %let ds=%scan(&source,2,.);
629  %let col=%scan(&source,3,.);
630  %put &=source;
631  %put &=lib;
632  %dc_assignlib(READ,&lib)
633  proc sql;
634  create table dqdata&x as
635  select distinct "&&base_col&x" as base_col length=32
636  ,"&source" as rule_value length=74
637  ,cats(&col) as rule_data length=1000
638  ,&col as tmp_order
639  from &lib..&ds
640  order by tmp_order;
641  /* ensure both numerics and char vals are ordered correctly */
642  data work.dqdata&x (drop=tmp_order);
643  set work.dqdata&x;
644  selectbox_order=_n_;
645  run;
646  %mp_abort(iftrue= (&syscc ne 0)
647  ,mac=&_program
648  ,msg=%str(syscc=&syscc when selecting &&base_col&x from &orig_libds)
649  )
650  proc append base=dqdata data=dqdata&x;run;
651  proc sql; drop table dqdata&x;
652  %end;
653 %mend dq_selects;
654 %dq_selects()
655 
656 proc sort data=dqdata;
657  /* order by selectbox_order then the value */
658  by base_col selectbox_order rule_data;
659 run;
660 
661 %mp_getmaxvarlengths(work.sasdata1,outds=maxvarlengths)
662 
663 data maxvarlengths;
664  set maxvarlengths;
665  if name='_____DELETE__THIS__RECORD_____' then mAXLEN=3;
666 run;
667 
668 data xl_rules;
669  set &mpelib..mpe_excel_config;
670  where &dc_dttmtfmt. lt tx_to;
671  where also upcase(xl_libref)="%scan(&orig_libds,1,.)";
672  where also upcase(xl_table)="%scan(&orig_libds,2,.)";
673  where also xl_active=1;
674  keep xl_column xl_rule;
675 run;
676 
677 %mpe_dsmeta(&libds, outds=dsmeta)
678 
679 %mpe_getversions(&mpelib,
680  %scan(&orig_libds,1,.),
681  %scan(&orig_libds,2,.),
682  outds=versions
683 )
684 
685 
686 /* send to the client */
687 %webout(OPEN)
688 %webout(OBJ,approvers)
689 %webout(OBJ,cols)
690 %webout(OBJ,dqdata)
691 %webout(OBJ,dqrules)
692 %webout(OBJ,dsmeta)
693 %webout(OBJ,maxvarlengths)
694 %webout(OBJ,query)
695 %webout(OBJ,sasdata1,fmt=N,missing=STRING,showmeta=YES,dslabel=sasdata)
696 %webout(OBJ,sasparams)
697 %webout(OBJ,versions)
698 %webout(OBJ,xl_rules)
699 %webout(CLOSE)
700 
701 /*
702 $N8601Bw
703 $N8601BAw
704 $N8601Ew
705 $N8601EAw
706 $N8601EHw
707 $N8601EXw
708 $N8601Hw
709 $N8601Xw
710 B8601DAw
711 B8601DNw
712 B8601DTw
713 B8601DZw
714 B8601LZw
715 B8601TMw
716 B8601TZw
717 DATEw
718 DATEAMPMw
719 DATETIMEw
720 DAYw
721 DDMMYYw
722 DDMMYYxw
723 DOWNAMEw
724 DTDATEw
725 DTMONYYw
726 DTWKDATXw
727 DTYEARw
728 DTYYQCw
729 E8601DAw
730 E8601DNw
731 E8601DTw
732 E8601DZw
733 E8601LZw
734 E8601TMw
735 E8601TZw
736 HHMMw
737 HOURw
738 JULDAYw
739 JULIANw
740 MMDDYYw
741 MMDDYYxw
742 MMSSw
743 MMYYw
744 MMYYxw
745 MONNAMEw
746 MONTHw
747 MONYYw
748 PDJULGw
749 PDJULIw
750 QTRw
751 QTRRw
752 TIMEw
753 TIMEAMPMw
754 TODw
755 WEEKDATEw
756 WEEKDATXw
757 WEEKDAYw
758 WEEKUw
759 WEEKVw
760 WEEKWw
761 WORDDATEw
762 WORDDATXw
763 YEARw
764 YYMMw
765 YYMMxw
766 YYMMDDw
767 YYMMDDxw
768 YYMONw
769 YYQw
770 YYQxw
771 YYQRw
772 YYQRxw
773 $N8601BAw
774 $N8601Ew
775 $N8601EAw
776 $N8601EHw
777 $N8601EXw
778 $N8601Hw
779 $N8601Xw
780 B8601DAw
781 B8601DNw
782 B8601DTw
783 B8601DZw
784 B8601LZw
785 B8601TMw
786 B8601TZw
787 E8601DAw
788 E8601DNw
789 E8601DTw
790 E8601DZw
791 E8601LZw
792 E8601TMw
793 E8601TZw
794 */
795 %mpeterm()