@sasjs/utils 2.49.0 → 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 (144) hide show
  1. package/fs/internal/helper.js +19 -24
  2. package/fs/internal/helper.js.map +1 -1
  3. package/macros/mf_abort.sas +27 -0
  4. package/macros/mf_dedup.sas +53 -0
  5. package/macros/mf_deletefile.sas +31 -0
  6. package/macros/mf_existds.sas +30 -0
  7. package/macros/mf_existfeature.sas +59 -0
  8. package/macros/mf_existfileref.sas +33 -0
  9. package/macros/mf_existfunction.sas +37 -0
  10. package/macros/mf_existvar.sas +39 -0
  11. package/macros/mf_existvarlist.sas +56 -0
  12. package/macros/mf_fmtdttm.sas +42 -0
  13. package/macros/mf_getapploc.sas +78 -0
  14. package/macros/mf_getattrc.sas +34 -0
  15. package/macros/mf_getattrn.sas +34 -0
  16. package/macros/mf_getengine.sas +54 -0
  17. package/macros/mf_getfilesize.sas +64 -0
  18. package/macros/mf_getfmtlist.sas +61 -0
  19. package/macros/mf_getfmtname.sas +44 -0
  20. package/macros/mf_getkeyvalue.sas +32 -0
  21. package/macros/mf_getplatform.sas +75 -0
  22. package/macros/mf_getquotedstr.sas +57 -0
  23. package/macros/mf_getschema.sas +43 -0
  24. package/macros/mf_getuniquefileref.sas +60 -0
  25. package/macros/mf_getuniquelibref.sas +57 -0
  26. package/macros/mf_getuniquename.sas +22 -0
  27. package/macros/mf_getuser.sas +44 -0
  28. package/macros/mf_getvalue.sas +36 -0
  29. package/macros/mf_getvarcount.sas +49 -0
  30. package/macros/mf_getvarformat.sas +72 -0
  31. package/macros/mf_getvarlen.sas +56 -0
  32. package/macros/mf_getvarlist.sas +74 -0
  33. package/macros/mf_getvarnum.sas +58 -0
  34. package/macros/mf_getvartype.sas +52 -0
  35. package/macros/mf_getxengine.sas +43 -0
  36. package/macros/mf_increment.sas +29 -0
  37. package/macros/mf_isblank.sas +27 -0
  38. package/macros/mf_isdir.sas +34 -0
  39. package/macros/mf_isint.sas +36 -0
  40. package/macros/mf_islibds.sas +40 -0
  41. package/macros/mf_loc.sas +29 -0
  42. package/macros/mf_mkdir.sas +67 -0
  43. package/macros/mf_mval.sas +19 -0
  44. package/macros/mf_nobs.sas +26 -0
  45. package/macros/mf_trimstr.sas +50 -0
  46. package/macros/mf_uid.sas +21 -0
  47. package/macros/mf_verifymacvars.sas +72 -0
  48. package/macros/mf_wordsinstr1andstr2.sas +53 -0
  49. package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
  50. package/macros/mf_writefile.sas +67 -0
  51. package/macros/mp_abort.sas +301 -0
  52. package/macros/mp_appendfile.sas +57 -0
  53. package/macros/mp_applyformats.sas +181 -0
  54. package/macros/mp_assert.sas +56 -0
  55. package/macros/mp_assertcols.sas +145 -0
  56. package/macros/mp_assertcolvals.sas +168 -0
  57. package/macros/mp_assertdsobs.sas +121 -0
  58. package/macros/mp_assertscope.sas +147 -0
  59. package/macros/mp_base64copy.sas +117 -0
  60. package/macros/mp_binarycopy.sas +79 -0
  61. package/macros/mp_chop.sas +194 -0
  62. package/macros/mp_cleancsv.sas +78 -0
  63. package/macros/mp_cntlout.sas +85 -0
  64. package/macros/mp_copyfolder.sas +84 -0
  65. package/macros/mp_coretable.sas +73 -0
  66. package/macros/mp_createconstraints.sas +70 -0
  67. package/macros/mp_createwebservice.sas +32 -0
  68. package/macros/mp_csv2ds.sas +140 -0
  69. package/macros/mp_deleteconstraints.sas +52 -0
  70. package/macros/mp_deletefolder.sas +70 -0
  71. package/macros/mp_dictionary.sas +52 -0
  72. package/macros/mp_dirlist.sas +263 -0
  73. package/macros/mp_distinctfmtvalues.sas +50 -0
  74. package/macros/mp_dropmembers.sas +46 -0
  75. package/macros/mp_ds2cards.sas +291 -0
  76. package/macros/mp_ds2csv.sas +212 -0
  77. package/macros/mp_ds2ddl.sas +30 -0
  78. package/macros/mp_ds2fmtds.sas +105 -0
  79. package/macros/mp_ds2inserts.sas +180 -0
  80. package/macros/mp_ds2md.sas +103 -0
  81. package/macros/mp_ds2squeeze.sas +120 -0
  82. package/macros/mp_dsmeta.sas +110 -0
  83. package/macros/mp_filtercheck.sas +251 -0
  84. package/macros/mp_filtergenerate.sas +105 -0
  85. package/macros/mp_filterstore.sas +254 -0
  86. package/macros/mp_filtervalidate.sas +105 -0
  87. package/macros/mp_getcols.sas +67 -0
  88. package/macros/mp_getconstraints.sas +115 -0
  89. package/macros/mp_getdbml.sas +335 -0
  90. package/macros/mp_getddl.sas +400 -0
  91. package/macros/mp_getformats.sas +124 -0
  92. package/macros/mp_getmaxvarlengths.sas +130 -0
  93. package/macros/mp_getpk.sas +281 -0
  94. package/macros/mp_gsubfile.sas +58 -0
  95. package/macros/mp_guesspk.sas +332 -0
  96. package/macros/mp_hashdataset.sas +91 -0
  97. package/macros/mp_hashdirectory.sas +162 -0
  98. package/macros/mp_include.sas +106 -0
  99. package/macros/mp_init.sas +76 -0
  100. package/macros/mp_jsonout.sas +406 -0
  101. package/macros/mp_lib2cards.sas +78 -0
  102. package/macros/mp_lib2inserts.sas +77 -0
  103. package/macros/mp_loadformat.sas +303 -0
  104. package/macros/mp_lockanytable.sas +243 -0
  105. package/macros/mp_lockfilecheck.sas +103 -0
  106. package/macros/mp_makedata.sas +107 -0
  107. package/macros/mp_md5.sas +58 -0
  108. package/macros/mp_perflog.sas +43 -0
  109. package/macros/mp_prevobs.sas +88 -0
  110. package/macros/mp_recursivejoin.sas +90 -0
  111. package/macros/mp_replace.sas +151 -0
  112. package/macros/mp_reseterror.sas +27 -0
  113. package/macros/mp_resetoption.sas +39 -0
  114. package/macros/mp_retainedkey.sas +247 -0
  115. package/macros/mp_runddl.sas +49 -0
  116. package/macros/mp_searchcols.sas +103 -0
  117. package/macros/mp_searchdata.sas +131 -0
  118. package/macros/mp_setkeyvalue.sas +55 -0
  119. package/macros/mp_sortinplace.sas +122 -0
  120. package/macros/mp_stackdiffs.sas +592 -0
  121. package/macros/mp_storediffs.sas +230 -0
  122. package/macros/mp_stprequests.sas +74 -0
  123. package/macros/mp_streamfile.sas +212 -0
  124. package/macros/mp_testjob.sas +92 -0
  125. package/macros/mp_testservice.sas +39 -0
  126. package/macros/mp_testwritespeedlibrary.sas +59 -0
  127. package/macros/mp_tree.sas +71 -0
  128. package/macros/mp_unzip.sas +90 -0
  129. package/macros/mp_updatevarlength.sas +93 -0
  130. package/macros/mp_validatecol.sas +97 -0
  131. package/macros/mp_wait4file.sas +35 -0
  132. package/macros/mp_webin.sas +59 -0
  133. package/macros/mp_zip.sas +85 -0
  134. package/package.json +4 -1
  135. package/scripts/copySASjsCore.ts +36 -0
  136. package/utils/index.d.ts +1 -2
  137. package/utils/index.js +2 -3
  138. package/utils/index.js.map +1 -1
  139. package/utils/utils.d.ts +1 -0
  140. package/utils/utils.js +7 -1
  141. package/utils/utils.js.map +1 -1
  142. package/utils/getNodeModulePath.d.ts +0 -2
  143. package/utils/getNodeModulePath.js +0 -83
  144. package/utils/getNodeModulePath.js.map +0 -1
@@ -0,0 +1,254 @@
1
+ /**
2
+ @file
3
+ @brief Checks & Stores an input filter table and returns the Filter Key
4
+ @details Used to generate a FILTER_RK from an input query dataset. This
5
+ process requires several permanent tables (names are configurable). The
6
+ benefit of storing query values at backend is to enable stored 'views' of
7
+ filtered tables at frontend (ie, when building [SAS-Powered Apps](
8
+ https://sasapps.io)). This macro is also used in [Data Controller for SAS](
9
+ https://datacontroller.io).
10
+
11
+ A more recent feature of this macro is the ability to support filter queries
12
+ on Format Catalogs. This is achieved by adding a `-FC` suffix to the `libds`
13
+ parameter - where the "ds" in this case is the catalog name.
14
+
15
+
16
+ @param [in] libds= The target dataset to be filtered (lib should be assigned).
17
+ If filtering a format catalog, add the following suffix: `-FC`.
18
+ @param [in] queryds= (WORK.FILTERQUERY) The temporary input query dataset to
19
+ be validated. Has the following format:
20
+ |GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$32767|
21
+ |---|---|---|---|---|---|
22
+ |AND|AND|1|SOME_BESTNUM|>|1|
23
+ |AND|AND|1|SOME_TIME|=|77333|
24
+ @param [in] filter_summary= (PERM.FILTER_SUMMARY) Permanent table containing
25
+ summary filter values. The definition is available by running
26
+ mp_coretable.sas as follows: `mp_coretable(FILTER_SUMMARY)`. Example
27
+ values:
28
+ |FILTER_RK:best.|FILTER_HASH:$32.|FILTER_TABLE:$41.|PROCESSED_DTTM:datetime19.|
29
+ |---|---|---|---|
30
+ |`1 `|`540E96F566D194AB58DD4C413C99C9DB `|`VIYA6014.MPE_TABLES `|`1956084246 `|
31
+ |`2 `|`87737DB9EEE2650F5C89956CEAD0A14F `|`VIYA6014.MPE_X_TEST `|`1956084452.1`|
32
+ |`3 `|`8048BD908DBBD83D013560734E90D394 `|`VIYA6014.MPE_TABLES `|`1956093620.6`|
33
+ @param [in] filter_detail= (PERM.FILTER_DETAIL) Permanent table containing
34
+ detailed (raw) filter values. The definition is available by running
35
+ mp_coretable.sas as follows: `mp_coretable(FILTER_DETAIL)`. Example
36
+ values:
37
+ |FILTER_HASH:$32.|FILTER_LINE:best.|GROUP_LOGIC:$3.|SUBGROUP_LOGIC:$3.|SUBGROUP_ID:best.|VARIABLE_NM:$32.|OPERATOR_NM:$12.|RAW_VALUE:$4000.|PROCESSED_DTTM:datetime19.|
38
+ |---|---|---|---|---|---|---|---|---|
39
+ |`540E96F566D194AB58DD4C413C99C9DB `|`1 `|`AND `|`AND `|`1 `|`LIBREF `|`CONTAINS `|`DC`|`1956084245.8 `|
40
+ |`540E96F566D194AB58DD4C413C99C9DB `|`2 `|`AND `|`OR `|`2 `|`DSN `|`= `|` MPE_LOCK_ANYTABLE `|`1956084245.8 `|
41
+ |`87737DB9EEE2650F5C89956CEAD0A14F `|`1 `|`AND `|`AND `|`1 `|`PRIMARY_KEY_FIELD `|`IN `|`(1,2,3) `|`1956084451.9 `|
42
+ @param [in] lock_table= (PERM.LOCK_TABLE) Permanent locking table. Used to
43
+ manage concurrent access. The definition is available by running
44
+ mp_coretable.sas as follows: `mp_coretable(LOCKTABLE)`.
45
+ @param [in] maxkeytable= (0) Optional permanent reference table used for
46
+ retained key tracking. Described in mp_retainedkey.sas.
47
+ @param [in] mdebug= set to 1 to enable DEBUG messages
48
+ @param [out] outresult= The result table with the FILTER_RK
49
+ @param [out] outquery= The original query, taken as extract after table load
50
+
51
+
52
+ <h4> SAS Macros </h4>
53
+ @li mddl_sas_cntlout.sas
54
+ @li mf_getuniquename.sas
55
+ @li mf_getvalue.sas
56
+ @li mf_islibds.sas
57
+ @li mf_nobs.sas
58
+ @li mp_abort.sas
59
+ @li mp_filtercheck.sas
60
+ @li mp_hashdataset.sas
61
+ @li mp_retainedkey.sas
62
+
63
+ <h4> Related Macros </h4>
64
+ @li mp_filtercheck.sas
65
+ @li mp_filtergenerate.sas
66
+ @li mp_filtervalidate.sas
67
+ @li mp_filterstore.test.sas
68
+
69
+ @version 9.2
70
+ @author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
71
+
72
+ **/
73
+
74
+ %macro mp_filterstore(libds=,
75
+ queryds=work.filterquery,
76
+ filter_summary=PERM.FILTER_SUMMARY,
77
+ filter_detail=PERM.FILTER_DETAIL,
78
+ lock_table=PERM.LOCK_TABLE,
79
+ maxkeytable=PERM.MAXKEYTABLE,
80
+ outresult=work.result,
81
+ outquery=work.query,
82
+ mdebug=1
83
+ );
84
+ %put &sysmacroname entry vars:;
85
+ %put _local_;
86
+
87
+ %local ds0 ds1 ds2 ds3 ds4 filter_hash orig_libds;
88
+ %let libds=%upcase(&libds);
89
+ %let orig_libds=&libds;
90
+
91
+ %mp_abort(iftrue= (&syscc ne 0)
92
+ ,mac=mp_filterstore
93
+ ,msg=%str(syscc=&syscc on macro entry)
94
+ )
95
+ %mp_abort(iftrue= (%mf_islibds(&filter_summary)=0)
96
+ ,mac=mp_filterstore
97
+ ,msg=%str(Invalid filter_summary value: &filter_summary)
98
+ )
99
+ %mp_abort(iftrue= (%mf_islibds(&filter_detail)=0)
100
+ ,mac=mp_filterstore
101
+ ,msg=%str(Invalid filter_detail value: &filter_detail)
102
+ )
103
+ %mp_abort(iftrue= (%mf_islibds(&lock_table)=0)
104
+ ,mac=mp_filterstore
105
+ ,msg=%str(Invalid lock_table value: &lock_table)
106
+ )
107
+
108
+ /**
109
+ * validate query
110
+ * use format catalog export, if a format
111
+ */
112
+ %if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do;
113
+ %let libds=%scan(&libds,1,-); /* chop off -FC extension */
114
+ %let ds0=%mf_getuniquename(prefix=fmtds_);
115
+ %let libds=&ds0;
116
+ /*
117
+ There is no need to export the entire format catalog here - the validations
118
+ are done against the data model, not the data values. So we can simply
119
+ hardcode the structure based on the cntlout dataset.
120
+ */
121
+ %mddl_sas_cntlout(libds=&ds0)
122
+
123
+ %end;
124
+ %mp_filtercheck(&queryds,targetds=&libds,abort=YES)
125
+
126
+ /* hash the result */
127
+ %let ds1=%mf_getuniquename(prefix=hashds);
128
+ %mp_hashdataset(&queryds,outds=&ds1,salt=&orig_libds)
129
+ %let filter_hash=%upcase(%mf_getvalue(&ds1,hashkey));
130
+ %if &mdebug=1 %then %do;
131
+ data _null_;
132
+ putlog "filter_hash=&filter_hash";
133
+ set &ds1;
134
+ putlog (_all_)(=);
135
+ run;
136
+ %end;
137
+
138
+ /* check if data already exists for this hash */
139
+ data &outresult;
140
+ set &filter_summary;
141
+ where filter_hash="&filter_hash";
142
+ run;
143
+
144
+ %mp_abort(iftrue= (&syscc ne 0)
145
+ ,mac=mp_filterstore
146
+ ,msg=%str(syscc=&syscc after hash check)
147
+ )
148
+ %mp_abort(iftrue= ("&filter_hash "=" ")
149
+ ,mac=mp_filterstore
150
+ ,msg=%str(problem with filter_hash generation)
151
+ )
152
+
153
+ %if %mf_nobs(&outresult)=0 %then %do;
154
+
155
+ /* first update summary table */
156
+ %let ds3=%mf_getuniquename(prefix=filtersum);
157
+ data work.&ds3;
158
+ if 0 then set &filter_summary;
159
+ filter_table="&orig_libds";
160
+ filter_hash="&filter_hash";
161
+ PROCESSED_DTTM=%sysfunc(datetime());
162
+ output;
163
+ stop;
164
+ run;
165
+
166
+ %mp_lockanytable(LOCK,
167
+ lib=%scan(&filter_summary,1,.)
168
+ ,ds=%scan(&filter_summary,2,.)
169
+ ,ref=MP_FILTERSTORE summary update - &filter_hash
170
+ ,ctl_ds=&lock_table
171
+ )
172
+
173
+ %let ds4=%mf_getuniquename(prefix=filtersumappend);
174
+ %mp_retainedkey(
175
+ base_lib=%scan(&filter_summary,1,.)
176
+ ,base_dsn=%scan(&filter_summary,2,.)
177
+ ,append_lib=work
178
+ ,append_dsn=&ds3
179
+ ,retained_key=filter_rk
180
+ ,business_key=filter_hash
181
+ ,maxkeytable=&maxkeytable
182
+ ,locktable=&lock_table
183
+ ,outds=work.&ds4
184
+ )
185
+ proc append base=&filter_summary data=&ds4;
186
+ run;
187
+
188
+ %mp_lockanytable(UNLOCK,
189
+ lib=%scan(&filter_summary,1,.)
190
+ ,ds=%scan(&filter_summary,2,.)
191
+ ,ref=MP_FILTERSTORE summary update - &filter_hash
192
+ ,ctl_ds=&lock_table
193
+ )
194
+
195
+ %if &syscc ne 0 %then %do;
196
+ data _null_;
197
+ set &ds4;
198
+ putlog (_all_)(=);
199
+ run;
200
+ %goto err;
201
+ %end;
202
+
203
+ data &outresult;
204
+ set &filter_summary;
205
+ where filter_hash="&filter_hash";
206
+ run;
207
+
208
+ /* Next, update detail table */
209
+ %let ds2=%mf_getuniquename(prefix=filterdetail);
210
+ data &ds2;
211
+ if 0 then set &filter_detail;
212
+ set &queryds;
213
+ format filter_hash $hex32. filter_line 8.;
214
+ filter_hash="&filter_hash";
215
+ filter_line=_n_;
216
+ PROCESSED_DTTM=%sysfunc(datetime());
217
+ run;
218
+ %mp_lockanytable(LOCK,
219
+ lib=%scan(&filter_detail,1,.)
220
+ ,ds=%scan(&filter_detail,2,.)
221
+ ,ref=MP_FILTERSTORE update - &filter_hash
222
+ ,ctl_ds=&lock_table
223
+ )
224
+ proc append base=&filter_detail data=&ds2;
225
+ run;
226
+
227
+ %mp_lockanytable(UNLOCK,
228
+ lib=%scan(&filter_detail,1,.)
229
+ ,ds=%scan(&filter_detail,2,.)
230
+ ,ref=MP_FILTERSTORE detail update &filter_hash
231
+ ,ctl_ds=&lock_table
232
+ )
233
+
234
+ %if &syscc ne 0 %then %do;
235
+ data _null_;
236
+ set &ds2;
237
+ putlog (_all_)(=);
238
+ run;
239
+ %goto err;
240
+ %end;
241
+
242
+ %end;
243
+
244
+ proc sort data=&filter_detail(where=(filter_hash="&filter_hash")) out=&outquery;
245
+ by filter_line;
246
+ run;
247
+
248
+ %err:
249
+ %mp_abort(iftrue= (&syscc ne 0)
250
+ ,mac=mp_filterstore
251
+ ,msg=%str(syscc=&syscc on macro exit)
252
+ )
253
+
254
+ %mend mp_filterstore;
@@ -0,0 +1,105 @@
1
+ /**
2
+ @file
3
+ @brief Checks a generated filter query for validity
4
+ @details Runs a generated filter in proc sql with the validate option.
5
+ Used in mp_filtercheck.sas in an fcmp container.
6
+
7
+ Built to support dynamic filtering in
8
+ [Data Controller for SAS&reg;](https://datacontroller.io).
9
+
10
+ Usage:
11
+
12
+ data work.filtertable;
13
+ infile datalines4 dsd;
14
+ input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
15
+ OPERATOR_NM:$10. RAW_VALUE:$4000.;
16
+ datalines4;
17
+ AND,AND,1,AGE,=,12
18
+ AND,AND,1,SEX,<=,"'M'"
19
+ AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
20
+ AND,OR,2,Weight,>=,7
21
+ ;;;;
22
+ run;
23
+
24
+ %mp_filtergenerate(work.filtertable,outref=myfilter)
25
+
26
+ %mp_filtervalidate(myfilter,sashelp.class)
27
+
28
+
29
+ @returns The SYSCC value will be 1008 if there are validation issues.
30
+
31
+ @param [in] inref The input fileref to validate (generated by
32
+ mp_filtergenerate.sas)
33
+ @param [in] targetds The target dataset against which to verify the query
34
+ @param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
35
+ @param [out] outds= (work.mp_filtervalidate) Output dataset containing the
36
+ err / warning message, if one exists. If this table contains any rows,
37
+ there are problems!
38
+
39
+ <h4> SAS Macros </h4>
40
+ @li mf_getuniquefileref.sas
41
+ @li mf_nobs.sas
42
+ @li mp_abort.sas
43
+
44
+ <h4> Related Macros </h4>
45
+ @li mp_filtercheck.sas
46
+ @li mp_filtergenerate.sas
47
+
48
+ @version 9.3
49
+ @author Allan Bowe
50
+
51
+ **/
52
+
53
+ %macro mp_filtervalidate(inref,targetds,abort=YES,outds=work.mp_filtervalidate);
54
+
55
+ %mp_abort(iftrue= (&syscc ne 0 or &syserr ne 0)
56
+ ,mac=&sysmacroname
57
+ ,msg=%str(syscc=&syscc / syserr=&syserr - on macro entry)
58
+ )
59
+
60
+ %local fref1;
61
+ %let fref1=%mf_getuniquefileref();
62
+
63
+ data _null_;
64
+ file &fref1;
65
+ infile &inref end=eof;
66
+ if _n_=1 then do;
67
+ put "proc sql;";
68
+ put "validate select * from &targetds";
69
+ put "where " ;
70
+ end;
71
+ input;
72
+ put _infile_;
73
+ putlog _infile_;
74
+ if eof then put ";quit;";
75
+ run;
76
+
77
+ %inc &fref1;
78
+
79
+ data &outds;
80
+ if &sqlrc or &syscc or &syserr then do;
81
+ REASON_CD='VALIDATION_ERR'!!'OR: '!!
82
+ coalescec(symget('SYSERRORTEXT'),symget('SYSWARNINGTEXT'));
83
+ output;
84
+ end;
85
+ else stop;
86
+ run;
87
+
88
+ filename &fref1 clear;
89
+
90
+ %if %mf_nobs(&outds)>0 %then %do;
91
+ %if &abort=YES %then %do;
92
+ data _null_;
93
+ set &outds;
94
+ call symputx('REASON_CD',reason_cd,'l');
95
+ stop;
96
+ run;
97
+ %mp_abort(
98
+ mac=&sysmacroname,
99
+ msg=%str(Filter validation issues.)
100
+ )
101
+ %end;
102
+ %let syscc=1008;
103
+ %end;
104
+
105
+ %mend mp_filtervalidate;
@@ -0,0 +1,67 @@
1
+ /**
2
+ @file
3
+ @brief Creates a dataset with column metadata.
4
+ @details This macro takes the `proc contents` output and "tidies it up" in the
5
+ following ways:
6
+
7
+ @li Blank labels are filled in with column names
8
+ @li Formats are reconstructed with default values
9
+ @li Types such as DATE / TIME / DATETIME are inferred from the formats
10
+
11
+ Example usage:
12
+
13
+ %mp_getcols(sashelp.airline,outds=work.myds)
14
+
15
+ @param ds The dataset from which to obtain column metadata
16
+ @param outds= (work.cols) The output dataset to create. Sample data:
17
+ |NAME:$32.|LENGTH:best.|VARNUM:best.|LABEL:$256.|FMTNAME:$32.|FORMAT:$49.|TYPE:$1.|DDTYPE:$9.|
18
+ |---|---|---|---|---|---|---|---|
19
+ |`AIR `|`8 `|`2 `|`international airline travel (thousands) `|` `|`8. `|`N `|`NUMERIC `|
20
+ |`DATE `|`8 `|`1 `|`DATE `|`MONYY `|`MONYY. `|`N `|`DATE `|
21
+ |`REGION `|`3 `|`3 `|`REGION `|` `|`$3. `|`C `|`CHARACTER `|
22
+
23
+ <h4> Related Macros </h4>
24
+ @li mf_getvarlist.sas
25
+ @li mm_getcols.sas
26
+
27
+ @version 9.2
28
+ @author Allan Bowe
29
+
30
+ **/
31
+
32
+ %macro mp_getcols(ds, outds=work.cols);
33
+ %local dropds;
34
+ proc contents noprint data=&ds
35
+ out=_data_ (keep=name type length label varnum format:);
36
+ run;
37
+ %let dropds=&syslast;
38
+ data &outds(keep=name type length varnum format label ddtype fmtname);
39
+ set &dropds(rename=(format=fmtname type=type2));
40
+ name=upcase(name);
41
+ if type2=2 then do;
42
+ length format $49.;
43
+ if fmtname='' then format=cats('$',length,'.');
44
+ else if formatl=0 then format=cats(fmtname,'.');
45
+ else format=cats(fmtname,formatl,'.');
46
+ type='C';
47
+ ddtype='CHARACTER';
48
+ end;
49
+ else do;
50
+ if fmtname='' then format=cats(length,'.');
51
+ else if formatl=0 then format=cats(fmtname,'.');
52
+ else if formatd=0 then format=cats(fmtname,formatl,'.');
53
+ else format=cats(fmtname,formatl,'.',formatd);
54
+ type='N';
55
+ if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME';
56
+ else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
57
+ or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
58
+ or format=:'MONYY'
59
+ then ddtype='DATE';
60
+ else if format=:'TIME' then ddtype='TIME';
61
+ else ddtype='NUMERIC';
62
+ end;
63
+ if label='' then label=name;
64
+ run;
65
+ proc sql;
66
+ drop table &dropds;
67
+ %mend mp_getcols;
@@ -0,0 +1,115 @@
1
+ /**
2
+ @file mp_getconstraints.sas
3
+ @brief Get constraint details at column level
4
+ @details Useful for capturing constraints before they are dropped / reapplied
5
+ during an update.
6
+
7
+ proc sql;
8
+ create table work.example(
9
+ TX_FROM float format=datetime19.,
10
+ DD_TYPE char(16),
11
+ DD_SOURCE char(2048),
12
+ DD_SHORTDESC char(256),
13
+ constraint pk primary key(tx_from, dd_type,dd_source),
14
+ constraint unq unique(tx_from, dd_type),
15
+ constraint nnn not null(DD_SHORTDESC)
16
+ );
17
+
18
+ %mp_getconstraints(lib=work,ds=example,outds=work.constraints)
19
+
20
+ @param [in] lib= (WORK) The target library
21
+ @param [in] ds= The target dataset. Leave blank (default) for all datasets.
22
+ @param [in] mdebug= (0) Set to 1 to preserve temp tables, print var values etc
23
+ @param [out] outds= (mp_getconstraints) the output dataset
24
+
25
+ <h4> SAS Macros </h4>
26
+ @li mf_getuniquename.sas
27
+ @li mp_dropmembers.sas
28
+
29
+ @version 9.2
30
+ @author Allan Bowe
31
+
32
+ **/
33
+
34
+ %macro mp_getconstraints(lib=WORK
35
+ ,ds=
36
+ ,outds=mp_getconstraints
37
+ ,mdebug=0
38
+ )/*/STORE SOURCE*/;
39
+
40
+ %let lib=%upcase(&lib);
41
+ %let ds=%upcase(&ds);
42
+
43
+ /**
44
+ * Cater for environments where sashelp.vcncolu is not available
45
+ */
46
+ %if %sysfunc(exist(sashelp.vcncolu,view))=0 %then %do;
47
+ proc sql;
48
+ create table &outds(
49
+ libref char(8)
50
+ ,TABLE_NAME char(32)
51
+ ,constraint_type char(8) label='Constraint Type'
52
+ ,constraint_name char(32) label='Constraint Name'
53
+ ,column_name char(32) label='Column'
54
+ ,constraint_order num
55
+ );
56
+ %return;
57
+ %end;
58
+
59
+ /**
60
+ * Neither dictionary tables nor sashelp provides a constraint order column,
61
+ * however they DO arrive in the correct order. So, create the col.
62
+ **/
63
+ %local vw;
64
+ %let vw=%mf_getuniquename(prefix=mp_getconstraints_vw_);
65
+ data &vw /view=&vw;
66
+ set sashelp.vcncolu;
67
+ where table_catalog="&lib";
68
+
69
+ /* use retain approach to reset the constraint order with each constraint */
70
+ length tmp $1000;
71
+ retain tmp;
72
+ drop tmp;
73
+ if tmp ne catx('|',table_catalog,table_name,constraint_name) then do;
74
+ constraint_order=1;
75
+ end;
76
+ else constraint_order+1;
77
+ tmp=catx('|',table_catalog, table_name,constraint_name);
78
+ run;
79
+
80
+ /* must use SQL as proc datasets does not support length changes */
81
+ proc sql noprint;
82
+ create table &outds as
83
+ select upcase(a.TABLE_CATALOG) as libref
84
+ ,upcase(a.TABLE_NAME) as TABLE_NAME
85
+ ,a.constraint_type
86
+ ,a.constraint_name
87
+ ,b.column_name
88
+ ,b.constraint_order
89
+ from dictionary.TABLE_CONSTRAINTS a
90
+ left join &vw b
91
+ on upcase(a.TABLE_CATALOG)=upcase(b.TABLE_CATALOG)
92
+ and upcase(a.TABLE_NAME)=upcase(b.TABLE_NAME)
93
+ and a.constraint_name=b.constraint_name
94
+ /**
95
+ * We cannot apply this clause to the underlying dictionary table. See:
96
+ * https://communities.sas.com/t5/SAS-Programming/Unexpected-Where-Clause-behaviour-in-dictionary-TABLE/m-p/771554#M244867
97
+ * cannot use`where calculated libref="&lib"` either as it will STILL execute
98
+ * all the underlying constraint queries, causing exception errors in some
99
+ * cases: https://github.com/sasjs/core/issues/283
100
+ */
101
+ where a.TABLE_CATALOG="&lib"
102
+ %if "&ds" ne "" %then %do;
103
+ and upcase(a.TABLE_NAME)="&ds"
104
+ and upcase(b.TABLE_NAME)="&ds"
105
+ %end;
106
+ order by libref, table_name, constraint_name, constraint_order
107
+ ;
108
+
109
+ /* tidy up */
110
+ %mp_dropmembers(
111
+ &vw,
112
+ iftrue=(&mdebug=0)
113
+ )
114
+
115
+ %mend mp_getconstraints;