@sasjs/utils 2.48.2 → 2.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/fs/generateCompileProgram.d.ts +1 -0
  2. package/fs/generateCompileProgram.js +154 -0
  3. package/fs/generateCompileProgram.js.map +1 -0
  4. package/fs/hash.d.ts +22 -0
  5. package/fs/hash.js +225 -0
  6. package/fs/hash.js.map +1 -0
  7. package/fs/index.d.ts +3 -0
  8. package/fs/index.js +13 -0
  9. package/fs/index.js.map +1 -0
  10. package/fs/internal/helper.d.ts +4 -0
  11. package/fs/internal/helper.js +125 -0
  12. package/fs/internal/helper.js.map +1 -0
  13. package/fs/sync.d.ts +6 -0
  14. package/fs/sync.js +208 -0
  15. package/fs/sync.js.map +1 -0
  16. package/index.d.ts +1 -0
  17. package/index.js +1 -0
  18. package/index.js.map +1 -1
  19. package/macros/mf_abort.sas +27 -0
  20. package/macros/mf_dedup.sas +53 -0
  21. package/macros/mf_deletefile.sas +31 -0
  22. package/macros/mf_existds.sas +30 -0
  23. package/macros/mf_existfeature.sas +59 -0
  24. package/macros/mf_existfileref.sas +33 -0
  25. package/macros/mf_existfunction.sas +37 -0
  26. package/macros/mf_existvar.sas +39 -0
  27. package/macros/mf_existvarlist.sas +56 -0
  28. package/macros/mf_fmtdttm.sas +42 -0
  29. package/macros/mf_getapploc.sas +78 -0
  30. package/macros/mf_getattrc.sas +34 -0
  31. package/macros/mf_getattrn.sas +34 -0
  32. package/macros/mf_getengine.sas +54 -0
  33. package/macros/mf_getfilesize.sas +64 -0
  34. package/macros/mf_getfmtlist.sas +61 -0
  35. package/macros/mf_getfmtname.sas +44 -0
  36. package/macros/mf_getkeyvalue.sas +32 -0
  37. package/macros/mf_getplatform.sas +75 -0
  38. package/macros/mf_getquotedstr.sas +57 -0
  39. package/macros/mf_getschema.sas +43 -0
  40. package/macros/mf_getuniquefileref.sas +60 -0
  41. package/macros/mf_getuniquelibref.sas +57 -0
  42. package/macros/mf_getuniquename.sas +22 -0
  43. package/macros/mf_getuser.sas +44 -0
  44. package/macros/mf_getvalue.sas +36 -0
  45. package/macros/mf_getvarcount.sas +49 -0
  46. package/macros/mf_getvarformat.sas +72 -0
  47. package/macros/mf_getvarlen.sas +56 -0
  48. package/macros/mf_getvarlist.sas +74 -0
  49. package/macros/mf_getvarnum.sas +58 -0
  50. package/macros/mf_getvartype.sas +52 -0
  51. package/macros/mf_getxengine.sas +43 -0
  52. package/macros/mf_increment.sas +29 -0
  53. package/macros/mf_isblank.sas +27 -0
  54. package/macros/mf_isdir.sas +34 -0
  55. package/macros/mf_isint.sas +36 -0
  56. package/macros/mf_islibds.sas +40 -0
  57. package/macros/mf_loc.sas +29 -0
  58. package/macros/mf_mkdir.sas +67 -0
  59. package/macros/mf_mval.sas +19 -0
  60. package/macros/mf_nobs.sas +26 -0
  61. package/macros/mf_trimstr.sas +50 -0
  62. package/macros/mf_uid.sas +21 -0
  63. package/macros/mf_verifymacvars.sas +72 -0
  64. package/macros/mf_wordsinstr1andstr2.sas +53 -0
  65. package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
  66. package/macros/mf_writefile.sas +67 -0
  67. package/macros/mp_abort.sas +301 -0
  68. package/macros/mp_appendfile.sas +57 -0
  69. package/macros/mp_applyformats.sas +181 -0
  70. package/macros/mp_assert.sas +56 -0
  71. package/macros/mp_assertcols.sas +145 -0
  72. package/macros/mp_assertcolvals.sas +168 -0
  73. package/macros/mp_assertdsobs.sas +121 -0
  74. package/macros/mp_assertscope.sas +147 -0
  75. package/macros/mp_base64copy.sas +117 -0
  76. package/macros/mp_binarycopy.sas +79 -0
  77. package/macros/mp_chop.sas +194 -0
  78. package/macros/mp_cleancsv.sas +78 -0
  79. package/macros/mp_cntlout.sas +85 -0
  80. package/macros/mp_copyfolder.sas +84 -0
  81. package/macros/mp_coretable.sas +73 -0
  82. package/macros/mp_createconstraints.sas +70 -0
  83. package/macros/mp_createwebservice.sas +32 -0
  84. package/macros/mp_csv2ds.sas +140 -0
  85. package/macros/mp_deleteconstraints.sas +52 -0
  86. package/macros/mp_deletefolder.sas +70 -0
  87. package/macros/mp_dictionary.sas +52 -0
  88. package/macros/mp_dirlist.sas +263 -0
  89. package/macros/mp_distinctfmtvalues.sas +50 -0
  90. package/macros/mp_dropmembers.sas +46 -0
  91. package/macros/mp_ds2cards.sas +291 -0
  92. package/macros/mp_ds2csv.sas +212 -0
  93. package/macros/mp_ds2ddl.sas +30 -0
  94. package/macros/mp_ds2fmtds.sas +105 -0
  95. package/macros/mp_ds2inserts.sas +180 -0
  96. package/macros/mp_ds2md.sas +103 -0
  97. package/macros/mp_ds2squeeze.sas +120 -0
  98. package/macros/mp_dsmeta.sas +110 -0
  99. package/macros/mp_filtercheck.sas +251 -0
  100. package/macros/mp_filtergenerate.sas +105 -0
  101. package/macros/mp_filterstore.sas +254 -0
  102. package/macros/mp_filtervalidate.sas +105 -0
  103. package/macros/mp_getcols.sas +67 -0
  104. package/macros/mp_getconstraints.sas +115 -0
  105. package/macros/mp_getdbml.sas +335 -0
  106. package/macros/mp_getddl.sas +400 -0
  107. package/macros/mp_getformats.sas +124 -0
  108. package/macros/mp_getmaxvarlengths.sas +130 -0
  109. package/macros/mp_getpk.sas +281 -0
  110. package/macros/mp_gsubfile.sas +58 -0
  111. package/macros/mp_guesspk.sas +332 -0
  112. package/macros/mp_hashdataset.sas +91 -0
  113. package/macros/mp_hashdirectory.sas +162 -0
  114. package/macros/mp_include.sas +106 -0
  115. package/macros/mp_init.sas +76 -0
  116. package/macros/mp_jsonout.sas +406 -0
  117. package/macros/mp_lib2cards.sas +78 -0
  118. package/macros/mp_lib2inserts.sas +77 -0
  119. package/macros/mp_loadformat.sas +303 -0
  120. package/macros/mp_lockanytable.sas +243 -0
  121. package/macros/mp_lockfilecheck.sas +103 -0
  122. package/macros/mp_makedata.sas +107 -0
  123. package/macros/mp_md5.sas +58 -0
  124. package/macros/mp_perflog.sas +43 -0
  125. package/macros/mp_prevobs.sas +88 -0
  126. package/macros/mp_recursivejoin.sas +90 -0
  127. package/macros/mp_replace.sas +151 -0
  128. package/macros/mp_reseterror.sas +27 -0
  129. package/macros/mp_resetoption.sas +39 -0
  130. package/macros/mp_retainedkey.sas +247 -0
  131. package/macros/mp_runddl.sas +49 -0
  132. package/macros/mp_searchcols.sas +103 -0
  133. package/macros/mp_searchdata.sas +131 -0
  134. package/macros/mp_setkeyvalue.sas +55 -0
  135. package/macros/mp_sortinplace.sas +122 -0
  136. package/macros/mp_stackdiffs.sas +592 -0
  137. package/macros/mp_storediffs.sas +230 -0
  138. package/macros/mp_stprequests.sas +74 -0
  139. package/macros/mp_streamfile.sas +212 -0
  140. package/macros/mp_testjob.sas +92 -0
  141. package/macros/mp_testservice.sas +39 -0
  142. package/macros/mp_testwritespeedlibrary.sas +59 -0
  143. package/macros/mp_tree.sas +71 -0
  144. package/macros/mp_unzip.sas +90 -0
  145. package/macros/mp_updatevarlength.sas +93 -0
  146. package/macros/mp_validatecol.sas +97 -0
  147. package/macros/mp_wait4file.sas +35 -0
  148. package/macros/mp_webin.sas +59 -0
  149. package/macros/mp_zip.sas +85 -0
  150. package/package.json +5 -2
  151. package/scripts/copySASjsCore.ts +36 -0
  152. package/types/hash.d.ts +9 -0
  153. package/types/hash.js +3 -0
  154. package/types/hash.js.map +1 -0
  155. package/types/index.d.ts +1 -0
  156. package/types/index.js +1 -0
  157. package/types/index.js.map +1 -1
  158. package/utils/index.d.ts +1 -1
  159. package/utils/index.js +2 -1
  160. package/utils/index.js.map +1 -1
  161. package/utils/utils.d.ts +1 -0
  162. package/utils/utils.js +7 -1
  163. package/utils/utils.js.map +1 -1
@@ -0,0 +1,301 @@
1
+ /**
2
+ @file
3
+ @brief abort gracefully according to context
4
+ @details Configures an abort mechanism according to site specific policies or
5
+ the particulars of an environment. For instance, can stream custom
6
+ results back to the client in an STP Web App context, or completely stop
7
+ in the case of a batch run. For STP sessions
8
+
9
+ The method used varies according to the context. Important points:
10
+
11
+ @li should not use endsas or abort cancel in 9.4m3 WIN environments as this
12
+ can cause hung multibridge sessions and result in a frozen STP server
13
+ @li The use of endsas in 9.4m6+ windows environments for POST requests to the
14
+ STP server can result in an empty response body
15
+ @li should not use endsas in viya 3.5 as this destroys the session and cannot
16
+ fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will
17
+ recognise this and fetch the log of the parent session instead)
18
+ @li STP environments must finish cleanly to avoid the log being sent to
19
+ _webout. To assist with this, we also run stpsrvset('program error', 0)
20
+ and set SYSCC=0.
21
+ Where possible, we take a unique "soft abort" approach - we open a macro
22
+ but don't close it! This works everywhere EXCEPT inside a \%include inside
23
+ a macro. For that, we recommend you use mp_include.sas to perform the
24
+ include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie,
25
+ OUTSIDE of the top-parent macro).
26
+ The soft abort has become ineffective in 9.4m6 WINDOWS environments. We are
27
+ currently investigating approaches to deal with this.
28
+
29
+
30
+ @param mac= (mp_abort.sas) To contain the name of the calling macro. Do not
31
+ use &sysmacroname as this will always resolve to MP_ABORT.
32
+ @param msg= message to be returned
33
+ @param iftrue= (1=1) Supply a condition for which the macro should be executed
34
+ @param errds= (work.mp_abort_errds) There is no clean way to end a process
35
+ within a %include called within a macro. Furthermore, there is no way to
36
+ test if a macro is called within a %include. To handle this particular
37
+ scenario, the %include should be switched for the mp_include.sas macro.
38
+ This provides an indicator that we are running a macro within a \%include
39
+ (`_SYSINCLUDEFILEDEVICE`) and allows us to provide a dataset with the abort
40
+ values (msg, mac).
41
+ We can then run an abort cancel FILE to stop the include running, and pass
42
+ the dataset back to the calling program to run a regular \%mp_abort().
43
+ The dataset will contain the following fields:
44
+ @li iftrue (1=1)
45
+ @li msg (the message)
46
+ @li mac (the mac param)
47
+
48
+ @param mode= (REGULAR) If mode=INCLUDE then the &errds dataset is checked for
49
+ an abort status.
50
+ Valid values:
51
+ @li REGULAR (default)
52
+ @li INCLUDE
53
+
54
+ @version 9.4
55
+ @author Allan Bowe
56
+
57
+ <h4> Related Macros </h4>
58
+ @li mp_include.sas
59
+
60
+ @cond
61
+ **/
62
+
63
+ %macro mp_abort(mac=mp_abort.sas, type=, msg=, iftrue=%str(1=1)
64
+ , errds=work.mp_abort_errds
65
+ , mode=REGULAR
66
+ )/*/STORE SOURCE*/;
67
+
68
+ %global sysprocessmode sysprocessname sasjs_stpsrv_header_loc sasjsprocessmode;
69
+ %local fref fid i;
70
+
71
+ %if not(%eval(%unquote(&iftrue))) %then %return;
72
+
73
+ %put NOTE: /// mp_abort macro executing //;
74
+ %if %length(&mac)>0 %then %put NOTE- called by &mac;
75
+ %put NOTE - &msg;
76
+
77
+ %if %symexist(_SYSINCLUDEFILEDEVICE)
78
+ /* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
79
+ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
80
+ %then %do;
81
+ %if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
82
+ data &errds;
83
+ iftrue='1=1';
84
+ length mac $100 msg $5000;
85
+ mac=symget('mac');
86
+ msg=symget('msg');
87
+ run;
88
+ data _null_;
89
+ abort cancel FILE;
90
+ run;
91
+ %return;
92
+ %end;
93
+ %end;
94
+
95
+ /* Web App Context */
96
+ %if %symexist(_PROGRAM)
97
+ or %superq(SYSPROCESSNAME) = %str(Compute Server)
98
+ or &mode=INCLUDE
99
+ %then %do;
100
+ options obs=max replace mprint;
101
+ %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
102
+ %then %do;
103
+ options nosyntaxcheck;
104
+ %end;
105
+
106
+ %if &mode=INCLUDE %then %do;
107
+ %if %sysfunc(exist(&errds))=1 %then %do;
108
+ data _null_;
109
+ set &errds;
110
+ call symputx('iftrue',iftrue,'l');
111
+ call symputx('mac',mac,'l');
112
+ call symputx('msg',msg,'l');
113
+ putlog (_all_)(=);
114
+ run;
115
+ %if (&iftrue)=0 %then %return;
116
+ %end;
117
+ %else %do;
118
+ %put &sysmacroname: No include errors found;
119
+ %return;
120
+ %end;
121
+ %end;
122
+
123
+ /* extract log errs / warns, if exist */
124
+ %local logloc logline;
125
+ %global logmsg; /* capture global messages */
126
+ %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
127
+ %else %let logloc=%qsysfunc(getoption(LOG));
128
+ proc printto log=log;run;
129
+ %let logline=0;
130
+ %if %length(&logloc)>0 %then %do;
131
+ data _null_;
132
+ infile &logloc lrecl=5000;
133
+ input; putlog _infile_;
134
+ i=1;
135
+ retain logonce 0;
136
+ if (
137
+ _infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
138
+ ) and logonce=0 then
139
+ do;
140
+ call symputx('logline',_n_);
141
+ logonce+1;
142
+ end;
143
+ run;
144
+ /* capture log including lines BEFORE the err */
145
+ %if &logline>0 %then %do;
146
+ data _null_;
147
+ infile &logloc lrecl=5000;
148
+ input;
149
+ i=1;
150
+ stoploop=0;
151
+ if _n_ ge &logline-15 and stoploop=0 then do until (i>22);
152
+ call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
153
+ input;
154
+ i+1;
155
+ stoploop=1;
156
+ end;
157
+ if stoploop=1 then stop;
158
+ run;
159
+ %end;
160
+ %end;
161
+
162
+ %if %symexist(SYS_JES_JOB_URI) %then %do;
163
+ /* setup webout for Viya */
164
+ options nobomfile;
165
+ %if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
166
+ filename _webout temp lrecl=999999 mod;
167
+ %end;
168
+ %else %do;
169
+ filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
170
+ name="_webout.json" lrecl=999999 mod;
171
+ %end;
172
+ %end;
173
+ %else %if %sysfunc(filename(fref,&sasjs_stpsrv_header_loc))=0 %then %do;
174
+ options nobomfile;
175
+ /* set up http header for SASjs Server */
176
+ %let fid=%sysfunc(fopen(&fref,A));
177
+ %if &fid=0 %then %do;
178
+ %put %str(ERR)OR: %sysfunc(sysmsg());
179
+ %return;
180
+ %end;
181
+ %let rc=%sysfunc(fput(&fid,%str(Content-Type: application/json)));
182
+ %let rc=%sysfunc(fwrite(&fid));
183
+ %let rc=%sysfunc(fclose(&fid));
184
+ %let rc=%sysfunc(filename(&fref));
185
+ %end;
186
+
187
+ /* send response in SASjs JSON format */
188
+ data _null_;
189
+ file _webout mod lrecl=32000 encoding='utf-8';
190
+ length msg syswarningtext syserrortext $32767 mode $10 ;
191
+ sasdatetime=datetime();
192
+ msg=symget('msg');
193
+ %if &logline>0 %then %do;
194
+ msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
195
+ %end;
196
+ /* escape the escapes */
197
+ msg=tranwrd(msg,'\','\\');
198
+ /* escape the quotes */
199
+ msg=tranwrd(msg,'"','\"');
200
+ /* ditch the CRLFs as chrome complains */
201
+ msg=compress(msg,,'kw');
202
+ /* quote without quoting the quotes (which are escaped instead) */
203
+ msg=cats('"',msg,'"');
204
+ if symexist('_debug') then debug=quote(trim(symget('_debug')));
205
+ else debug='""';
206
+ if symget('sasjsprocessmode')='Stored Program' then mode='SASJS';
207
+ if mode ne 'SASJS' then put '>>weboutBEGIN<<';
208
+ put '{"SYSDATE" : "' "&SYSDATE" '"';
209
+ put ',"SYSTIME" : "' "&SYSTIME" '"';
210
+ put ',"sasjsAbort" : [{';
211
+ put ' "MSG":' msg ;
212
+ put ' ,"MAC": "' "&mac" '"}]';
213
+ put ",""SYSUSERID"" : ""&sysuserid"" ";
214
+ put ',"_DEBUG":' debug ;
215
+ if symexist('_metauser') then do;
216
+ _METAUSER=quote(trim(symget('_METAUSER')));
217
+ put ",""_METAUSER"": " _METAUSER;
218
+ _METAPERSON=quote(trim(symget('_METAPERSON')));
219
+ put ',"_METAPERSON": ' _METAPERSON;
220
+ end;
221
+ if symexist('SYS_JES_JOB_URI') then do;
222
+ SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
223
+ put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
224
+ end;
225
+ _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
226
+ put ',"_PROGRAM" : ' _PROGRAM ;
227
+ put ",""SYSCC"" : ""&syscc"" ";
228
+ syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
229
+ put ",""SYSERRORTEXT"" : " syserrortext;
230
+ put ",""SYSHOSTNAME"" : ""&syshostname"" ";
231
+ put ",""SYSJOBID"" : ""&sysjobid"" ";
232
+ put ",""SYSSCPL"" : ""&sysscpl"" ";
233
+ put ",""SYSSITE"" : ""&syssite"" ";
234
+ sysvlong=quote(trim(symget('sysvlong')));
235
+ put ',"SYSVLONG" : ' sysvlong;
236
+ syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
237
+ put ",""SYSWARNINGTEXT"" : " syswarningtext;
238
+ put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
239
+ put "}" ;
240
+ if mode ne 'SASJS' then put '>>weboutEND<<';
241
+ run;
242
+
243
+ %put _all_;
244
+
245
+ %if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
246
+ data _null_;
247
+ putlog 'stpsrvset program err and syscc';
248
+ rc=stpsrvset('program error', 0);
249
+ call symputx("syscc",0,"g");
250
+ run;
251
+ %if &sysscp=WIN
252
+ and 1=0 /* deprecating this logic until we figure out a consistent abort */
253
+ and "%substr(%str(&sysvlong ),1,8)"="9.04.01M"
254
+ and "%substr(%str(&sysvlong ),9,1)">"5" %then %do;
255
+ /* skip approach (below) does not work in windows m6+ envs */
256
+ endsas;
257
+ %end;
258
+ %else %do;
259
+ /**
260
+ * endsas kills 9.4m3 deployments by orphaning multibridges.
261
+ * Abort variants are ungraceful (non zero return code)
262
+ * This approach lets SAS run silently until the end :-)
263
+ * Caution - fails when called within a %include within a macro
264
+ * Use mp_include() to handle this.
265
+ */
266
+ filename skip temp;
267
+ data _null_;
268
+ file skip;
269
+ put '%macro skip();';
270
+ comment '%mend skip; -> fix lint ';
271
+ put '%macro skippy();';
272
+ comment '%mend skippy; -> fix lint ';
273
+ run;
274
+ %inc skip;
275
+ %end;
276
+ %end;
277
+ %else %if "&sysprocessmode " = "SAS Compute Server " %then %do;
278
+ /* endsas kills the session making it harder to fetch results */
279
+ data _null_;
280
+ syswarningtext=symget('syswarningtext');
281
+ syserrortext=symget('syserrortext');
282
+ abort_msg=symget('msg');
283
+ syscc=symget('syscc');
284
+ sysuserid=symget('sysuserid');
285
+ iftrue=symget('iftrue');
286
+ put (_all_)(/=);
287
+ call symputx('syscc',0);
288
+ abort cancel nolist;
289
+ run;
290
+ %end;
291
+ %else %do;
292
+ %abort cancel;
293
+ %end;
294
+ %end;
295
+ %else %do;
296
+ %put _all_;
297
+ %abort cancel;
298
+ %end;
299
+ %mend mp_abort;
300
+
301
+ /** @endcond */
@@ -0,0 +1,57 @@
1
+ /**
2
+ @file
3
+ @brief Append (concatenate) two or more files.
4
+ @details Will append one more more `appendrefs` (filerefs) to a `baseref`.
5
+ Uses a binary mechanism, so will work with any file type. For that reason -
6
+ use with care! And supply your own trailing carriage returns in each file..
7
+
8
+ Usage:
9
+
10
+ filename tmp1 temp;
11
+ filename tmp2 temp;
12
+ filename tmp3 temp;
13
+ data _null_; file tmp1; put 'base file';
14
+ data _null_; file tmp2; put 'append1';
15
+ data _null_; file tmp3; put 'append2';
16
+ run;
17
+ %mp_appendfile(baseref=tmp1, appendrefs=tmp2 tmp3)
18
+
19
+
20
+ @param [in] baseref= Fileref of the base file (should exist)
21
+ @param [in] appendrefs= One or more filerefs to be appended to the base
22
+ fileref. Space separated.
23
+
24
+ @version 9.2
25
+ @author Allan Bowe, source: https://github.com/sasjs/core
26
+
27
+ <h4> SAS Macros </h4>
28
+ @li mp_abort.sas
29
+ @li mp_binarycopy.sas
30
+
31
+
32
+ **/
33
+
34
+ %macro mp_appendfile(
35
+ baseref=0,
36
+ appendrefs=0
37
+ )/*/STORE SOURCE*/;
38
+
39
+ %mp_abort(iftrue= (&baseref=0)
40
+ ,mac=&sysmacroname
41
+ ,msg=%str(Baseref NOT specified!)
42
+ )
43
+ %mp_abort(iftrue= (&appendrefs=0)
44
+ ,mac=&sysmacroname
45
+ ,msg=%str(Appendrefs NOT specified!)
46
+ )
47
+
48
+ %local i;
49
+ %do i=1 %to %sysfunc(countw(&appendrefs));
50
+ %mp_abort(iftrue= (&syscc>0)
51
+ ,mac=&sysmacroname
52
+ ,msg=%str(syscc=&syscc)
53
+ )
54
+ %mp_binarycopy(inref=%scan(&appendrefs,&i), outref=&baseref, mode=APPEND)
55
+ %end;
56
+
57
+ %mend mp_appendfile;
@@ -0,0 +1,181 @@
1
+ /**
2
+ @file
3
+ @brief Apply a set of formats to a table
4
+ @details Applies a set of formats to the metadata of one or more SAS datasets.
5
+ Can be used to migrate formats from one table to another. The input table
6
+ must contain the following columns:
7
+
8
+ @li lib - the libref of the table to be updated
9
+ @li ds - the dataset to be updated
10
+ @li var - the variable to be updated
11
+ @li fmt - the format to apply. Missing or default ($CHAR, 8.) formats are
12
+ ignored.
13
+
14
+ The macro will abort in the following scenarios:
15
+
16
+ @li Libref not assigned
17
+ @li Dataset does not exist
18
+ @li Input table contains null or invalid values
19
+
20
+ Example usage:
21
+
22
+ data work.example;
23
+ set sashelp.prdsale;
24
+ format _all_ clear;
25
+ run;
26
+
27
+ %mp_getcols(sashelp.prdsale,outds=work.cols)
28
+
29
+ data work.cols2;
30
+ set work.cols;
31
+ lib='WORK';
32
+ ds='EXAMPLE';
33
+ var=name;
34
+ fmt=format;
35
+ keep lib ds var fmt;
36
+ run;
37
+
38
+ %mp_applyformats(work.cols2)
39
+
40
+ @param [in] inds The input dataset containing the formats to apply (and where
41
+ to apply them). Example structure:
42
+ |LIB:$8.|DS:$32.|VAR:$32.|FMT:$49.|
43
+ |---|---|---|---|
44
+ |`WORK `|`EXAMPLE `|`ACTUAL `|`DOLLAR12.2 `|
45
+ |`WORK `|`EXAMPLE `|`COUNTRY `|`$CHAR10. `|
46
+ |`WORK `|`EXAMPLE `|`DIVISION `|`$CHAR10. `|
47
+ |`WORK `|`EXAMPLE `|`MONTH `|`MONNAME3. `|
48
+ |`WORK `|`EXAMPLE `|`PREDICT `|`DOLLAR12.2 `|
49
+ |`WORK `|`EXAMPLE `|`PRODTYPE `|`$CHAR10. `|
50
+ |`WORK `|`EXAMPLE `|`PRODUCT `|`$CHAR10. `|
51
+ |`WORK `|`EXAMPLE `|`QUARTER `|`8. `|
52
+ |`WORK `|`EXAMPLE `|`REGION `|`$CHAR10. `|
53
+ |`WORK `|`EXAMPLE `|`YEAR `|`8. `|
54
+
55
+ @param [out] errds= (0) Provide a libds reference here to export the
56
+ error messages to a table. In this case, they will not be printed to the
57
+ log.
58
+
59
+ <h4> SAS Macros </h4>
60
+ @li mf_getengine.sas
61
+ @li mf_getuniquefileref.sas
62
+ @li mf_getuniquename.sas
63
+ @li mf_nobs.sas
64
+ @li mp_validatecol.sas
65
+
66
+
67
+ <h4> Related Macros </h4>
68
+ @li mp_getformats.sas
69
+
70
+ @version 9.2
71
+ @author Allan Bowe
72
+
73
+ **/
74
+
75
+ %macro mp_applyformats(inds,errds=0
76
+ )/*/STORE SOURCE*/;
77
+ %local outds liblist i engine lib msg ;
78
+
79
+ /**
80
+ * Validations
81
+ */
82
+ proc sort data=&inds;
83
+ by lib ds var fmt;
84
+ run;
85
+
86
+ %if &errds=0 %then %let outds=%mf_getuniquename(prefix=mp_applyformats);
87
+ %else %let outds=&errds;
88
+
89
+ data &outds;
90
+ set &inds;
91
+ where fmt not in ('','.', '$', '$CHAR.','8.');
92
+ length msg $128;
93
+ by lib ds var fmt;
94
+ if libref(lib) ne 0 then do;
95
+ msg=catx(' ','libref',lib,'is not assigned!');
96
+ %if &errds=0 %then %do;
97
+ putlog "%str(ERR)OR: " msg;
98
+ %end;
99
+ output;
100
+ return;
101
+ end;
102
+ if exist(cats(lib,'.',ds)) ne 1 then do;
103
+ msg=catx(' ','libds',lib,'.',ds,'does not exist!');
104
+ %if &errds=0 %then %do;
105
+ putlog "%str(ERR)OR: " msg;
106
+ %end;
107
+ output;
108
+ return;
109
+ end;
110
+ %mp_validatecol(fmt,FORMAT,is_fmt)
111
+ if is_fmt=0 then do;
112
+ msg=catx(' ','format',fmt,'on libds',lib,'.',ds,'.',var,'is not valid!');
113
+ %if &errds=0 %then %do;
114
+ putlog "%str(ERR)OR: " msg;
115
+ %end;
116
+ output;
117
+ return;
118
+ end;
119
+
120
+ if first.ds then do;
121
+ retain dsid;
122
+ dsid=open(cats(lib,'.',ds));
123
+ if dsid=0 then do;
124
+ msg=catx(' ','libds',lib,'.',ds,' could not be opened!');
125
+ %if &errds=0 %then %do;
126
+ putlog "%str(ERR)OR: " msg;
127
+ %end;
128
+ output;
129
+ return;
130
+ end;
131
+ if varnum(dsid,var)<1 then do;
132
+ msg=catx(' ','Variable',lib,'.',ds,'.',var,' was not found!');
133
+ %if &errds=0 %then %do;
134
+ putlog "%str(ERR)OR: " msg;
135
+ %end;
136
+ output;
137
+ end;
138
+ end;
139
+ if last.ds then rc=close(dsid);
140
+ run;
141
+
142
+ proc sql noprint;
143
+ select distinct lib into: liblist separated by ' ' from &inds;
144
+ %put &=liblist;
145
+ %if %length(&liblist)>0 %then %do i=1 %to %sysfunc(countw(&liblist));
146
+ %let lib=%scan(&liblist,1);
147
+ %let engine=%mf_getengine(&lib);
148
+ %if &engine ne V9 and &engine ne BASE %then %do;
149
+ %let msg=&lib has &engine engine - formats cannot be applied;
150
+ insert into &outds set lib="&lib",ds="_all_",var="_all", msg="&msg" ;
151
+ %if &errds=0 %then %put %str(ERR)OR: &msg;
152
+ %end;
153
+ %end;
154
+ quit;
155
+
156
+ %if %mf_nobs(&outds)>0 %then %return;
157
+
158
+ /**
159
+ * Validations complete - now apply the actual formats!
160
+ */
161
+ %let fref=%mf_getuniquefileref();
162
+ data _null_;
163
+ set &inds;
164
+ by lib ds var fmt;
165
+ where fmt not in ('','.', '$', '$CHAR.','8.');
166
+ file &fref;
167
+ if first.lib then put 'proc datasets nolist lib=' lib ';';
168
+ if first.ds then put ' modify ' ds ';';
169
+ put ' format ' var fmt ';';
170
+ if last.ds then put ' run;';
171
+ if last.lib then put 'quit;';
172
+ run;
173
+
174
+ %inc &fref/source2;
175
+
176
+ %if &errds=0 %then %do;
177
+ proc sql;
178
+ drop table &outds;
179
+ %end;
180
+
181
+ %mend mp_applyformats;
@@ -0,0 +1,56 @@
1
+ /**
2
+ @file
3
+ @brief Generic assertion
4
+ @details Useful in the context of writing sasjs tests. The results of the
5
+ test are _appended_ to the &outds. table.
6
+
7
+ Example usage:
8
+
9
+ %mp_assert(iftrue=(1=1),
10
+ desc=Obviously true
11
+ )
12
+
13
+ %mp_assert(iftrue=(1=0),
14
+ desc=Will fail
15
+ )
16
+
17
+ @param [in] iftrue= (1=1) A condition where, if true, the test is a PASS.
18
+ Else, the test is a fail.
19
+
20
+ @param [in] desc= (Testing observations) The user provided test description
21
+ @param [out] outds= (work.test_results) The output dataset to contain the
22
+ results. If it does not exist, it will be created, with the following format:
23
+ |TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
24
+ |---|---|---|
25
+ |User Provided description|PASS|Column &inds contained ALL columns|
26
+
27
+ @version 9.2
28
+ @author Allan Bowe
29
+
30
+ **/
31
+
32
+ %macro mp_assert(iftrue=(1=1),
33
+ desc=0,
34
+ outds=work.test_results
35
+ )/*/STORE SOURCE*/;
36
+
37
+ data ;
38
+ length test_description $256 test_result $4 test_comments $256;
39
+ test_description=symget('desc');
40
+ test_comments="&sysmacroname: Test result of "!!symget('iftrue');
41
+ %if %eval(%unquote(&iftrue)) %then %do;
42
+ test_result='PASS';
43
+ %end;
44
+ %else %do;
45
+ test_result='FAIL';
46
+ %end;
47
+ run;
48
+
49
+ %local ds ;
50
+ %let ds=&syslast;
51
+ proc append base=&outds data=&ds;
52
+ run;
53
+ proc sql;
54
+ drop table &ds;
55
+
56
+ %mend mp_assert;