@sasjs/utils 2.49.0 → 2.49.2
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.
- package/fs/internal/helper.js +19 -24
- package/fs/internal/helper.js.map +1 -1
- package/macros/mf_abort.sas +27 -0
- package/macros/mf_dedup.sas +53 -0
- package/macros/mf_deletefile.sas +31 -0
- package/macros/mf_existds.sas +30 -0
- package/macros/mf_existfeature.sas +59 -0
- package/macros/mf_existfileref.sas +33 -0
- package/macros/mf_existfunction.sas +37 -0
- package/macros/mf_existvar.sas +39 -0
- package/macros/mf_existvarlist.sas +56 -0
- package/macros/mf_fmtdttm.sas +42 -0
- package/macros/mf_getapploc.sas +78 -0
- package/macros/mf_getattrc.sas +34 -0
- package/macros/mf_getattrn.sas +34 -0
- package/macros/mf_getengine.sas +54 -0
- package/macros/mf_getfilesize.sas +64 -0
- package/macros/mf_getfmtlist.sas +61 -0
- package/macros/mf_getfmtname.sas +44 -0
- package/macros/mf_getkeyvalue.sas +32 -0
- package/macros/mf_getplatform.sas +75 -0
- package/macros/mf_getquotedstr.sas +57 -0
- package/macros/mf_getschema.sas +43 -0
- package/macros/mf_getuniquefileref.sas +60 -0
- package/macros/mf_getuniquelibref.sas +57 -0
- package/macros/mf_getuniquename.sas +22 -0
- package/macros/mf_getuser.sas +44 -0
- package/macros/mf_getvalue.sas +36 -0
- package/macros/mf_getvarcount.sas +49 -0
- package/macros/mf_getvarformat.sas +72 -0
- package/macros/mf_getvarlen.sas +56 -0
- package/macros/mf_getvarlist.sas +74 -0
- package/macros/mf_getvarnum.sas +58 -0
- package/macros/mf_getvartype.sas +52 -0
- package/macros/mf_getxengine.sas +43 -0
- package/macros/mf_increment.sas +29 -0
- package/macros/mf_isblank.sas +27 -0
- package/macros/mf_isdir.sas +34 -0
- package/macros/mf_isint.sas +36 -0
- package/macros/mf_islibds.sas +40 -0
- package/macros/mf_loc.sas +29 -0
- package/macros/mf_mkdir.sas +67 -0
- package/macros/mf_mval.sas +19 -0
- package/macros/mf_nobs.sas +26 -0
- package/macros/mf_trimstr.sas +50 -0
- package/macros/mf_uid.sas +21 -0
- package/macros/mf_verifymacvars.sas +72 -0
- package/macros/mf_wordsinstr1andstr2.sas +53 -0
- package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
- package/macros/mf_writefile.sas +67 -0
- package/macros/mp_abort.sas +301 -0
- package/macros/mp_appendfile.sas +57 -0
- package/macros/mp_applyformats.sas +181 -0
- package/macros/mp_assert.sas +56 -0
- package/macros/mp_assertcols.sas +145 -0
- package/macros/mp_assertcolvals.sas +168 -0
- package/macros/mp_assertdsobs.sas +121 -0
- package/macros/mp_assertscope.sas +147 -0
- package/macros/mp_base64copy.sas +117 -0
- package/macros/mp_binarycopy.sas +79 -0
- package/macros/mp_chop.sas +194 -0
- package/macros/mp_cleancsv.sas +78 -0
- package/macros/mp_cntlout.sas +85 -0
- package/macros/mp_copyfolder.sas +84 -0
- package/macros/mp_coretable.sas +73 -0
- package/macros/mp_createconstraints.sas +70 -0
- package/macros/mp_createwebservice.sas +32 -0
- package/macros/mp_csv2ds.sas +140 -0
- package/macros/mp_deleteconstraints.sas +52 -0
- package/macros/mp_deletefolder.sas +70 -0
- package/macros/mp_dictionary.sas +52 -0
- package/macros/mp_dirlist.sas +262 -0
- package/macros/mp_distinctfmtvalues.sas +50 -0
- package/macros/mp_dropmembers.sas +46 -0
- package/macros/mp_ds2cards.sas +291 -0
- package/macros/mp_ds2csv.sas +212 -0
- package/macros/mp_ds2ddl.sas +30 -0
- package/macros/mp_ds2fmtds.sas +105 -0
- package/macros/mp_ds2inserts.sas +180 -0
- package/macros/mp_ds2md.sas +103 -0
- package/macros/mp_ds2squeeze.sas +120 -0
- package/macros/mp_dsmeta.sas +110 -0
- package/macros/mp_filtercheck.sas +251 -0
- package/macros/mp_filtergenerate.sas +105 -0
- package/macros/mp_filterstore.sas +254 -0
- package/macros/mp_filtervalidate.sas +105 -0
- package/macros/mp_getcols.sas +67 -0
- package/macros/mp_getconstraints.sas +115 -0
- package/macros/mp_getdbml.sas +335 -0
- package/macros/mp_getddl.sas +400 -0
- package/macros/mp_getformats.sas +124 -0
- package/macros/mp_getmaxvarlengths.sas +130 -0
- package/macros/mp_getpk.sas +281 -0
- package/macros/mp_gitadd.sas +45 -0
- package/macros/mp_gitreleaseinfo.sas +74 -0
- package/macros/mp_gitstatus.sas +67 -0
- package/macros/mp_gsubfile.sas +58 -0
- package/macros/mp_guesspk.sas +332 -0
- package/macros/mp_hashdataset.sas +91 -0
- package/macros/mp_hashdirectory.sas +164 -0
- package/macros/mp_include.sas +106 -0
- package/macros/mp_init.sas +76 -0
- package/macros/mp_jsonout.sas +406 -0
- package/macros/mp_lib2cards.sas +78 -0
- package/macros/mp_lib2inserts.sas +77 -0
- package/macros/mp_loadformat.sas +303 -0
- package/macros/mp_lockanytable.sas +243 -0
- package/macros/mp_lockfilecheck.sas +103 -0
- package/macros/mp_makedata.sas +107 -0
- package/macros/mp_md5.sas +58 -0
- package/macros/mp_perflog.sas +43 -0
- package/macros/mp_prevobs.sas +88 -0
- package/macros/mp_recursivejoin.sas +90 -0
- package/macros/mp_replace.sas +151 -0
- package/macros/mp_reseterror.sas +27 -0
- package/macros/mp_resetoption.sas +39 -0
- package/macros/mp_retainedkey.sas +247 -0
- package/macros/mp_runddl.sas +49 -0
- package/macros/mp_searchcols.sas +103 -0
- package/macros/mp_searchdata.sas +131 -0
- package/macros/mp_setkeyvalue.sas +55 -0
- package/macros/mp_sortinplace.sas +122 -0
- package/macros/mp_stackdiffs.sas +592 -0
- package/macros/mp_storediffs.sas +230 -0
- package/macros/mp_stprequests.sas +74 -0
- package/macros/mp_streamfile.sas +212 -0
- package/macros/mp_testjob.sas +92 -0
- package/macros/mp_testservice.sas +39 -0
- package/macros/mp_testwritespeedlibrary.sas +59 -0
- package/macros/mp_tree.sas +71 -0
- package/macros/mp_unzip.sas +90 -0
- package/macros/mp_updatevarlength.sas +93 -0
- package/macros/mp_validatecol.sas +97 -0
- package/macros/mp_wait4file.sas +35 -0
- package/macros/mp_webin.sas +59 -0
- package/macros/mp_zip.sas +85 -0
- package/package.json +5 -2
- package/scripts/copySASjsCore.ts +36 -0
- package/utils/index.d.ts +1 -2
- package/utils/index.js +2 -3
- package/utils/index.js.map +1 -1
- package/utils/utils.d.ts +1 -0
- package/utils/utils.js +7 -1
- package/utils/utils.js.map +1 -1
- package/utils/getNodeModulePath.d.ts +0 -2
- package/utils/getNodeModulePath.js +0 -83
- package/utils/getNodeModulePath.js.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Initialise session with useful settings and variables
|
|
4
|
+
@details Implements a "strict" set of SAS options for use in defensive
|
|
5
|
+
programming. Highly recommended, if you want your code to run on some
|
|
6
|
+
other machine.
|
|
7
|
+
|
|
8
|
+
This macro is recommended to be compiled and invoked in the `initProgram`
|
|
9
|
+
for SASjs [Jobs](https://cli.sasjs.io/sasjsconfig.html#jobConfig_initProgram
|
|
10
|
+
), [Services](
|
|
11
|
+
https://cli.sasjs.io/sasjsconfig.html#serviceConfig_initProgram) and [Tests]
|
|
12
|
+
(https://cli.sasjs.io/sasjsconfig.html#testConfig_initProgram).
|
|
13
|
+
|
|
14
|
+
For non SASjs projects, you could invoke in the autoexec, or in your own
|
|
15
|
+
solution initialisation macro.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
If you have a good idea for another useful option, setting, or global
|
|
19
|
+
variable - feel free to [raise an issue](
|
|
20
|
+
https://github.com/sasjs/core/issues/new)!
|
|
21
|
+
|
|
22
|
+
All global variables are prefixed with "SASJS" (unless modified with the
|
|
23
|
+
prefix parameter).
|
|
24
|
+
|
|
25
|
+
@param [in] prefix= (SASJS) The prefix to apply to the global macro variables
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@version 9.2
|
|
29
|
+
@author Allan Bowe
|
|
30
|
+
|
|
31
|
+
**/
|
|
32
|
+
|
|
33
|
+
%macro mp_init(prefix=SASJS
|
|
34
|
+
)/*/STORE SOURCE*/;
|
|
35
|
+
|
|
36
|
+
%if %symexist(SASJS_PREFIX) %then %return; /* only run once */
|
|
37
|
+
|
|
38
|
+
%global
|
|
39
|
+
SASJS_PREFIX /* the ONLY hard-coded global macro variable in SASjs */
|
|
40
|
+
&prefix._FUNCTIONS /* used in mcf_init() to track core function compilation */
|
|
41
|
+
&prefix._INIT_NUM /* initialisation time as numeric */
|
|
42
|
+
&prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */
|
|
43
|
+
&prefix.WORK /* avoid typing %sysfunc(pathname(work)) every time */
|
|
44
|
+
;
|
|
45
|
+
|
|
46
|
+
%let sasjs_prefix=&prefix;
|
|
47
|
+
|
|
48
|
+
data _null_;
|
|
49
|
+
dttm=datetime();
|
|
50
|
+
call symputx("&sasjs_prefix._init_num",dttm,'g');
|
|
51
|
+
call symputx("&sasjs_prefix._init_dttm",put(dttm,E8601DT26.6),'g');
|
|
52
|
+
call symputx("&sasjs_prefix.work",pathname('WORK'),'g');
|
|
53
|
+
run;
|
|
54
|
+
|
|
55
|
+
options
|
|
56
|
+
compress=CHAR /* default is none so ensure we have something! */
|
|
57
|
+
datastmtchk=ALLKEYWORDS /* protection from overwriting input datasets */
|
|
58
|
+
errorcheck=STRICT /* catch errs in libname/filename statements */
|
|
59
|
+
fmterr /* ensure err when a format cannot be found */
|
|
60
|
+
mergenoby=%str(ERR)OR /* throw err when a merge has no BY variables */
|
|
61
|
+
missing=. /* changing this can cause hard to detect errs */
|
|
62
|
+
noquotelenmax /* avoid warnings for long strings */
|
|
63
|
+
noreplace /* avoid overwriting permanent datasets */
|
|
64
|
+
ps=max /* reduce log size slightly */
|
|
65
|
+
ls=max /* reduce log even more and avoid word truncation */
|
|
66
|
+
validmemname=COMPATIBLE /* avoid special characters etc in table names */
|
|
67
|
+
validvarname=V7 /* avoid special characters etc in variable names */
|
|
68
|
+
varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */
|
|
69
|
+
varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */
|
|
70
|
+
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
|
|
71
|
+
noautocorrect /* disallow misspelled procedure names */
|
|
72
|
+
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
|
|
73
|
+
%end;
|
|
74
|
+
;
|
|
75
|
+
|
|
76
|
+
%mend mp_init;
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_jsonout.sas
|
|
3
|
+
@brief Writes JSON in SASjs format to a fileref
|
|
4
|
+
@details This macro can be used to OPEN a JSON stream and send one or more
|
|
5
|
+
tables as arrays of rows, where each row can be an object or a nested array.
|
|
6
|
+
|
|
7
|
+
There are two engines available - DATASTEP or PROCJSON.
|
|
8
|
+
|
|
9
|
+
PROC JSON is fast but will produce errs like the ones below if
|
|
10
|
+
special chars are encountered.
|
|
11
|
+
|
|
12
|
+
> (ERR)OR: Some code points did not transcode.
|
|
13
|
+
|
|
14
|
+
> An object or array close is not valid at this point in the JSON text.
|
|
15
|
+
|
|
16
|
+
> Date value out of range
|
|
17
|
+
|
|
18
|
+
If this happens, try running with ENGINE=DATASTEP.
|
|
19
|
+
|
|
20
|
+
The DATASTEP engine is used to handle special SAS missing numerics, and
|
|
21
|
+
can also convert entire datasets to formatted values. Output JSON is always
|
|
22
|
+
in UTF-8.
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
|
|
26
|
+
filename tmp temp;
|
|
27
|
+
data class; set sashelp.class;run;
|
|
28
|
+
|
|
29
|
+
%mp_jsonout(OPEN,jref=tmp)
|
|
30
|
+
%mp_jsonout(OBJ,class,jref=tmp)
|
|
31
|
+
%mp_jsonout(OBJ,class,dslabel=class2,jref=tmp,showmeta=Y)
|
|
32
|
+
%mp_jsonout(CLOSE,jref=tmp)
|
|
33
|
+
|
|
34
|
+
data _null_;
|
|
35
|
+
infile tmp;
|
|
36
|
+
input;putlog _infile_;
|
|
37
|
+
run;
|
|
38
|
+
|
|
39
|
+
If you are building web apps with SAS then you are strongly encouraged to use
|
|
40
|
+
the mX_createwebservice macros in combination with the
|
|
41
|
+
[sasjs adapter](https://github.com/sasjs/adapter).
|
|
42
|
+
For more information see https://sasjs.io
|
|
43
|
+
|
|
44
|
+
@param [in] action Valid values:
|
|
45
|
+
@li OPEN - opens the JSON
|
|
46
|
+
@li OBJ - sends a table with each row as an object
|
|
47
|
+
@li ARR - sends a table with each row in an array
|
|
48
|
+
@li CLOSE - closes the JSON
|
|
49
|
+
@param [in] ds The dataset to send. Must be a work table.
|
|
50
|
+
@param [out] jref= (_webout) The fileref to which to send the JSON
|
|
51
|
+
@param [out] dslabel= The name to give the table in the exported JSON
|
|
52
|
+
@param [in] fmt= (Y) Whether to keep (Y) or strip (N) formats from the table
|
|
53
|
+
@param [in] engine= (DATASTEP) Which engine to use to send the JSON. Options:
|
|
54
|
+
@li PROCJSON (default)
|
|
55
|
+
@li DATASTEP (more reliable when data has non standard characters)
|
|
56
|
+
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
|
57
|
+
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
|
58
|
+
@param [in] showmeta= (N) Set to Y to output metadata alongside each table,
|
|
59
|
+
such as the column formats and types. The metadata is contained inside an
|
|
60
|
+
object with the same name as the table but prefixed with a dollar sign - ie,
|
|
61
|
+
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
|
62
|
+
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
|
63
|
+
that should be converted to JSON
|
|
64
|
+
|
|
65
|
+
<h4> Related Files </h4>
|
|
66
|
+
@li mp_ds2fmtds.sas
|
|
67
|
+
|
|
68
|
+
@version 9.2
|
|
69
|
+
@author Allan Bowe
|
|
70
|
+
@source https://github.com/sasjs/core
|
|
71
|
+
|
|
72
|
+
**/
|
|
73
|
+
%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y
|
|
74
|
+
,engine=DATASTEP
|
|
75
|
+
,missing=NULL
|
|
76
|
+
,showmeta=N
|
|
77
|
+
,maxobs=MAX
|
|
78
|
+
)/*/STORE SOURCE*/;
|
|
79
|
+
%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval
|
|
80
|
+
tmpds1 tmpds2 tmpds3 tmpds4;
|
|
81
|
+
%let numcols=0;
|
|
82
|
+
%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;);
|
|
83
|
+
|
|
84
|
+
%if &action=OPEN %then %do;
|
|
85
|
+
options nobomfile;
|
|
86
|
+
data _null_;file &jref encoding='utf-8' lrecl=200;
|
|
87
|
+
put '{"PROCESSED_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '"';
|
|
88
|
+
run;
|
|
89
|
+
%end;
|
|
90
|
+
%else %if (&action=ARR or &action=OBJ) %then %do;
|
|
91
|
+
/* force variable names to always be uppercase in the JSON */
|
|
92
|
+
options validvarname=upcase;
|
|
93
|
+
/* To avoid issues with _webout on EBI - such as encoding diffs and truncation
|
|
94
|
+
(https://support.sas.com/kb/49/325.html) we use temporary files */
|
|
95
|
+
filename _sjs1 temp lrecl=200 ;
|
|
96
|
+
data _null_; file _sjs1 encoding='utf-8';
|
|
97
|
+
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
|
|
98
|
+
run;
|
|
99
|
+
/* now write to _webout 1 char at a time */
|
|
100
|
+
data _null_;
|
|
101
|
+
infile _sjs1 lrecl=1 recfm=n;
|
|
102
|
+
file &jref mod lrecl=1 recfm=n;
|
|
103
|
+
input sourcechar $char1. @@;
|
|
104
|
+
format sourcechar hex2.;
|
|
105
|
+
put sourcechar char1. @@;
|
|
106
|
+
run;
|
|
107
|
+
filename _sjs1 clear;
|
|
108
|
+
|
|
109
|
+
/* grab col defs */
|
|
110
|
+
proc contents noprint data=&ds
|
|
111
|
+
out=_data_(keep=name type length format formatl formatd varnum label);
|
|
112
|
+
run;
|
|
113
|
+
%let colinfo=%scan(&syslast,2,.);
|
|
114
|
+
proc sort data=&colinfo;
|
|
115
|
+
by varnum;
|
|
116
|
+
run;
|
|
117
|
+
/* move meta to mac vars */
|
|
118
|
+
data &colinfo;
|
|
119
|
+
if _n_=1 then call symputx('numcols',nobs,'l');
|
|
120
|
+
set &colinfo end=last nobs=nobs;
|
|
121
|
+
name=upcase(name);
|
|
122
|
+
/* fix formats */
|
|
123
|
+
if type=2 or type=6 then do;
|
|
124
|
+
typelong='char';
|
|
125
|
+
length fmt $49.;
|
|
126
|
+
if format='' then fmt=cats('$',length,'.');
|
|
127
|
+
else if formatl=0 then fmt=cats(format,'.');
|
|
128
|
+
else fmt=cats(format,formatl,'.');
|
|
129
|
+
end;
|
|
130
|
+
else do;
|
|
131
|
+
typelong='num';
|
|
132
|
+
if format='' then fmt='best.';
|
|
133
|
+
else if formatl=0 then fmt=cats(format,'.');
|
|
134
|
+
else if formatd=0 then fmt=cats(format,formatl,'.');
|
|
135
|
+
else fmt=cats(format,formatl,'.',formatd);
|
|
136
|
+
end;
|
|
137
|
+
/* 32 char unique name */
|
|
138
|
+
newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27);
|
|
139
|
+
|
|
140
|
+
call symputx(cats('name',_n_),name,'l');
|
|
141
|
+
call symputx(cats('newname',_n_),newname,'l');
|
|
142
|
+
call symputx(cats('length',_n_),length,'l');
|
|
143
|
+
call symputx(cats('fmt',_n_),fmt,'l');
|
|
144
|
+
call symputx(cats('type',_n_),type,'l');
|
|
145
|
+
call symputx(cats('typelong',_n_),typelong,'l');
|
|
146
|
+
call symputx(cats('label',_n_),coalescec(label,name),'l');
|
|
147
|
+
/* overwritten when fmt=Y and a custom format exists in catalog */
|
|
148
|
+
if typelong='num' then call symputx(cats('fmtlen',_n_),200,'l');
|
|
149
|
+
else call symputx(cats('fmtlen',_n_),min(32767,ceil((length+10)*1.5)),'l');
|
|
150
|
+
run;
|
|
151
|
+
|
|
152
|
+
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
|
153
|
+
proc sql;
|
|
154
|
+
select count(*) into: lastobs from &ds;
|
|
155
|
+
%if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs));
|
|
156
|
+
|
|
157
|
+
%if &engine=PROCJSON %then %do;
|
|
158
|
+
%if &missing=STRING %then %do;
|
|
159
|
+
%put &sysmacroname: Special Missings not supported in proc json.;
|
|
160
|
+
%put &sysmacroname: Switching to DATASTEP engine;
|
|
161
|
+
%goto datastep;
|
|
162
|
+
%end;
|
|
163
|
+
data &tempds;
|
|
164
|
+
set &ds;
|
|
165
|
+
&stmt_obs;
|
|
166
|
+
%if &fmt=N %then format _numeric_ best32.;;
|
|
167
|
+
/* PRETTY is necessary to avoid line truncation in large files */
|
|
168
|
+
filename _sjs2 temp lrecl=131068 encoding='utf-8';
|
|
169
|
+
proc json out=_sjs2 pretty
|
|
170
|
+
%if &action=ARR %then nokeys ;
|
|
171
|
+
;export &tempds / nosastags fmtnumeric;
|
|
172
|
+
run;
|
|
173
|
+
/* send back to webout */
|
|
174
|
+
data _null_;
|
|
175
|
+
infile _sjs2 lrecl=1 recfm=n;
|
|
176
|
+
file &jref mod lrecl=1 recfm=n;
|
|
177
|
+
input sourcechar $char1. @@;
|
|
178
|
+
format sourcechar hex2.;
|
|
179
|
+
put sourcechar char1. @@;
|
|
180
|
+
run;
|
|
181
|
+
filename _sjs2 clear;
|
|
182
|
+
%end;
|
|
183
|
+
%else %if &engine=DATASTEP %then %do;
|
|
184
|
+
%datastep:
|
|
185
|
+
%if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1
|
|
186
|
+
%then %do;
|
|
187
|
+
%put &sysmacroname: &ds NOT FOUND!!!;
|
|
188
|
+
%return;
|
|
189
|
+
%end;
|
|
190
|
+
|
|
191
|
+
%if &fmt=Y %then %do;
|
|
192
|
+
/**
|
|
193
|
+
* Extract format definitions
|
|
194
|
+
* First, by getting library locations from dictionary.formats
|
|
195
|
+
* Then, by exporting the width using proc format
|
|
196
|
+
* Cannot use maxw from sashelp.vformat as not always populated
|
|
197
|
+
* Cannot use fmtinfo() as not supported in all flavours
|
|
198
|
+
*/
|
|
199
|
+
%let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
|
200
|
+
%let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
|
201
|
+
%let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
|
202
|
+
%let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
|
203
|
+
proc sql noprint;
|
|
204
|
+
create table &tmpds1 as
|
|
205
|
+
select cats(libname,'.',memname) as FMTCAT,
|
|
206
|
+
FMTNAME
|
|
207
|
+
from dictionary.formats
|
|
208
|
+
where fmttype='F' and libname is not null
|
|
209
|
+
and fmtname in (select format from &colinfo where format is not null)
|
|
210
|
+
order by 1;
|
|
211
|
+
create table &tmpds2(
|
|
212
|
+
FMTNAME char(32),
|
|
213
|
+
LENGTH num
|
|
214
|
+
);
|
|
215
|
+
%local catlist cat fmtlist i;
|
|
216
|
+
select distinct fmtcat into: catlist separated by ' ' from &tmpds1;
|
|
217
|
+
%do i=1 %to %sysfunc(countw(&catlist,%str( )));
|
|
218
|
+
%let cat=%scan(&catlist,&i,%str( ));
|
|
219
|
+
proc sql;
|
|
220
|
+
select distinct fmtname into: fmtlist separated by ' '
|
|
221
|
+
from &tmpds1 where fmtcat="&cat";
|
|
222
|
+
proc format lib=&cat cntlout=&tmpds3(keep=fmtname length);
|
|
223
|
+
select &fmtlist;
|
|
224
|
+
run;
|
|
225
|
+
proc sql;
|
|
226
|
+
insert into &tmpds2 select distinct fmtname,length from &tmpds3;
|
|
227
|
+
%end;
|
|
228
|
+
|
|
229
|
+
proc sql;
|
|
230
|
+
create table &tmpds4 as
|
|
231
|
+
select a.*, b.length as MAXW
|
|
232
|
+
from &colinfo a
|
|
233
|
+
left join &tmpds2 b
|
|
234
|
+
on cats(a.format)=cats(upcase(b.fmtname))
|
|
235
|
+
order by a.varnum;
|
|
236
|
+
data _null_;
|
|
237
|
+
set &tmpds4;
|
|
238
|
+
if not missing(maxw);
|
|
239
|
+
call symputx(
|
|
240
|
+
cats('fmtlen',_n_),
|
|
241
|
+
/* vars need extra padding due to JSON escaping of special chars */
|
|
242
|
+
min(32767,ceil((max(length,maxw)+10)*1.5))
|
|
243
|
+
,'l'
|
|
244
|
+
);
|
|
245
|
+
run;
|
|
246
|
+
|
|
247
|
+
/* configure varlenchk - as we are explicitly shortening the variables */
|
|
248
|
+
%let optval=%sysfunc(getoption(varlenchk));
|
|
249
|
+
options varlenchk=NOWARN;
|
|
250
|
+
data _data_(compress=char);
|
|
251
|
+
/* shorten the new vars */
|
|
252
|
+
length
|
|
253
|
+
%do i=1 %to &numcols;
|
|
254
|
+
&&name&i $&&fmtlen&i
|
|
255
|
+
%end;
|
|
256
|
+
;
|
|
257
|
+
/* rename on entry */
|
|
258
|
+
set &ds(rename=(
|
|
259
|
+
%do i=1 %to &numcols;
|
|
260
|
+
&&name&i=&&newname&i
|
|
261
|
+
%end;
|
|
262
|
+
));
|
|
263
|
+
&stmt_obs;
|
|
264
|
+
|
|
265
|
+
drop
|
|
266
|
+
%do i=1 %to &numcols;
|
|
267
|
+
&&newname&i
|
|
268
|
+
%end;
|
|
269
|
+
;
|
|
270
|
+
%do i=1 %to &numcols;
|
|
271
|
+
%if &&typelong&i=num %then %do;
|
|
272
|
+
&&name&i=cats(put(&&newname&i,&&fmt&i));
|
|
273
|
+
%end;
|
|
274
|
+
%else %do;
|
|
275
|
+
&&name&i=put(&&newname&i,&&fmt&i);
|
|
276
|
+
%end;
|
|
277
|
+
%end;
|
|
278
|
+
if _error_ then do;
|
|
279
|
+
call symputx('syscc',1012);
|
|
280
|
+
stop;
|
|
281
|
+
end;
|
|
282
|
+
run;
|
|
283
|
+
%let fmtds=&syslast;
|
|
284
|
+
options varlenchk=&optval;
|
|
285
|
+
%end;
|
|
286
|
+
|
|
287
|
+
proc format; /* credit yabwon for special null removal */
|
|
288
|
+
value bart (default=40)
|
|
289
|
+
%if &missing=NULL %then %do;
|
|
290
|
+
._ - .z = null
|
|
291
|
+
%end;
|
|
292
|
+
%else %do;
|
|
293
|
+
._ = [quote()]
|
|
294
|
+
. = null
|
|
295
|
+
.a - .z = [quote()]
|
|
296
|
+
%end;
|
|
297
|
+
other = [best.];
|
|
298
|
+
|
|
299
|
+
data &tempds;
|
|
300
|
+
attrib _all_ label='';
|
|
301
|
+
%do i=1 %to &numcols;
|
|
302
|
+
%if &&typelong&i=char or &fmt=Y %then %do;
|
|
303
|
+
length &&name&i $&&fmtlen&i...;
|
|
304
|
+
format &&name&i $&&fmtlen&i...;
|
|
305
|
+
%end;
|
|
306
|
+
%end;
|
|
307
|
+
%if &fmt=Y %then %do;
|
|
308
|
+
set &fmtds;
|
|
309
|
+
%end;
|
|
310
|
+
%else %do;
|
|
311
|
+
set &ds;
|
|
312
|
+
%end;
|
|
313
|
+
&stmt_obs;
|
|
314
|
+
format _numeric_ bart.;
|
|
315
|
+
%do i=1 %to &numcols;
|
|
316
|
+
%if &&typelong&i=char or &fmt=Y %then %do;
|
|
317
|
+
if findc(&&name&i,'"\'!!'0A0D09000E0F010210111A'x) then do;
|
|
318
|
+
&&name&i='"'!!trim(
|
|
319
|
+
prxchange('s/"/\\"/',-1, /* double quote */
|
|
320
|
+
prxchange('s/\x0A/\n/',-1, /* new line */
|
|
321
|
+
prxchange('s/\x0D/\r/',-1, /* carriage return */
|
|
322
|
+
prxchange('s/\x09/\\t/',-1, /* tab */
|
|
323
|
+
prxchange('s/\x00/\\u0000/',-1, /* NUL */
|
|
324
|
+
prxchange('s/\x0E/\\u000E/',-1, /* SS */
|
|
325
|
+
prxchange('s/\x0F/\\u000F/',-1, /* SF */
|
|
326
|
+
prxchange('s/\x01/\\u0001/',-1, /* SOH */
|
|
327
|
+
prxchange('s/\x02/\\u0002/',-1, /* STX */
|
|
328
|
+
prxchange('s/\x10/\\u0010/',-1, /* DLE */
|
|
329
|
+
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
|
|
330
|
+
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
|
|
331
|
+
prxchange('s/\\/\\\\/',-1,&&name&i)
|
|
332
|
+
)))))))))))))!!'"';
|
|
333
|
+
end;
|
|
334
|
+
else &&name&i=quote(cats(&&name&i));
|
|
335
|
+
%end;
|
|
336
|
+
%end;
|
|
337
|
+
run;
|
|
338
|
+
|
|
339
|
+
filename _sjs3 temp lrecl=131068 ;
|
|
340
|
+
data _null_;
|
|
341
|
+
file _sjs3 encoding='utf-8';
|
|
342
|
+
if _n_=1 then put "[";
|
|
343
|
+
set &tempds;
|
|
344
|
+
if _n_>1 then put "," @; put
|
|
345
|
+
%if &action=ARR %then "[" ; %else "{" ;
|
|
346
|
+
%do i=1 %to &numcols;
|
|
347
|
+
%if &i>1 %then "," ;
|
|
348
|
+
%if &action=OBJ %then """&&name&i"":" ;
|
|
349
|
+
"&&name&i"n /* name literal for reserved variable names */
|
|
350
|
+
%end;
|
|
351
|
+
%if &action=ARR %then "]" ; %else "}" ; ;
|
|
352
|
+
|
|
353
|
+
/* close out the table */
|
|
354
|
+
data _null_;
|
|
355
|
+
file _sjs3 mod encoding='utf-8';
|
|
356
|
+
put ']';
|
|
357
|
+
run;
|
|
358
|
+
data _null_;
|
|
359
|
+
infile _sjs3 lrecl=1 recfm=n;
|
|
360
|
+
file &jref mod lrecl=1 recfm=n;
|
|
361
|
+
input sourcechar $char1. @@;
|
|
362
|
+
format sourcechar hex2.;
|
|
363
|
+
put sourcechar char1. @@;
|
|
364
|
+
run;
|
|
365
|
+
filename _sjs3 clear;
|
|
366
|
+
%end;
|
|
367
|
+
|
|
368
|
+
proc sql;
|
|
369
|
+
drop table &colinfo, &tempds;
|
|
370
|
+
|
|
371
|
+
%if %substr(&showmeta,1,1)=Y %then %do;
|
|
372
|
+
filename _sjs4 temp lrecl=131068 encoding='utf-8';
|
|
373
|
+
data _null_;
|
|
374
|
+
file _sjs4;
|
|
375
|
+
length label $350;
|
|
376
|
+
put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{";
|
|
377
|
+
do i=1 to &numcols;
|
|
378
|
+
name=quote(trim(symget(cats('name',i))));
|
|
379
|
+
format=quote(trim(symget(cats('fmt',i))));
|
|
380
|
+
label=quote(prxchange('s/\\/\\\\/',-1,trim(symget(cats('label',i)))));
|
|
381
|
+
length=quote(trim(symget(cats('length',i))));
|
|
382
|
+
type=quote(trim(symget(cats('typelong',i))));
|
|
383
|
+
if i>1 then put "," @@;
|
|
384
|
+
put name ':{"format":' format ',"label":' label
|
|
385
|
+
',"length":' length ',"type":' type '}';
|
|
386
|
+
end;
|
|
387
|
+
put '}}';
|
|
388
|
+
run;
|
|
389
|
+
/* send back to webout */
|
|
390
|
+
data _null_;
|
|
391
|
+
infile _sjs4 lrecl=1 recfm=n;
|
|
392
|
+
file &jref mod lrecl=1 recfm=n;
|
|
393
|
+
input sourcechar $char1. @@;
|
|
394
|
+
format sourcechar hex2.;
|
|
395
|
+
put sourcechar char1. @@;
|
|
396
|
+
run;
|
|
397
|
+
filename _sjs4 clear;
|
|
398
|
+
%end;
|
|
399
|
+
%end;
|
|
400
|
+
|
|
401
|
+
%else %if &action=CLOSE %then %do;
|
|
402
|
+
data _null_; file &jref encoding='utf-8' mod ;
|
|
403
|
+
put "}";
|
|
404
|
+
run;
|
|
405
|
+
%end;
|
|
406
|
+
%mend mp_jsonout;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Convert all library members to CARDS files
|
|
4
|
+
@details Gets list of members then calls the <code>%mp_ds2cards()</code> macro.
|
|
5
|
+
Usage:
|
|
6
|
+
|
|
7
|
+
%mp_lib2cards(lib=sashelp
|
|
8
|
+
, outloc= C:\temp )
|
|
9
|
+
|
|
10
|
+
The output will be one cards file in the `outloc` directory per dataset in the
|
|
11
|
+
input `lib` library. If the `outloc` directory does not exist, it is created.
|
|
12
|
+
|
|
13
|
+
To create a single SAS file with the first 1000 records of each table in a
|
|
14
|
+
library you could use this syntax:
|
|
15
|
+
|
|
16
|
+
%mp_lib2cards(lib=sashelp
|
|
17
|
+
, outloc= /tmp
|
|
18
|
+
, outfile= myfile.sas
|
|
19
|
+
, maxobs= 1000
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
<h4> SAS Macros </h4>
|
|
23
|
+
@li mf_mkdir.sas
|
|
24
|
+
@li mf_trimstr.sas
|
|
25
|
+
@li mp_ds2cards.sas
|
|
26
|
+
|
|
27
|
+
@param [in] lib= Library in which to convert all datasets
|
|
28
|
+
@param [out] outloc= Location in which to store output. Defaults to WORK
|
|
29
|
+
library. No quotes.
|
|
30
|
+
@param [out] outfile= Optional output file NAME - if provided, then will create
|
|
31
|
+
a single output file instead of one file per input table.
|
|
32
|
+
@param [in] maxobs= limit output to the first <code>maxobs</code> observations
|
|
33
|
+
|
|
34
|
+
@version 9.2
|
|
35
|
+
@author Allan Bowe
|
|
36
|
+
**/
|
|
37
|
+
|
|
38
|
+
%macro mp_lib2cards(lib=
|
|
39
|
+
,outloc=%sysfunc(pathname(work)) /* without trailing slash */
|
|
40
|
+
,maxobs=max
|
|
41
|
+
,random_sample=NO
|
|
42
|
+
,outfile=0
|
|
43
|
+
)/*/STORE SOURCE*/;
|
|
44
|
+
|
|
45
|
+
/* Find the tables */
|
|
46
|
+
%local x ds memlist;
|
|
47
|
+
proc sql noprint;
|
|
48
|
+
select distinct lowcase(memname)
|
|
49
|
+
into: memlist
|
|
50
|
+
separated by ' '
|
|
51
|
+
from dictionary.tables
|
|
52
|
+
where upcase(libname)="%upcase(&lib)";
|
|
53
|
+
|
|
54
|
+
/* trim trailing slash, if provided */
|
|
55
|
+
%let outloc=%mf_trimstr(&outloc,/);
|
|
56
|
+
%let outloc=%mf_trimstr(&outloc,\);
|
|
57
|
+
|
|
58
|
+
/* create the output directory */
|
|
59
|
+
%mf_mkdir(&outloc)
|
|
60
|
+
|
|
61
|
+
/* create the cards files */
|
|
62
|
+
%do x=1 %to %sysfunc(countw(&memlist));
|
|
63
|
+
%let ds=%scan(&memlist,&x);
|
|
64
|
+
%mp_ds2cards(base_ds=&lib..&ds
|
|
65
|
+
,maxobs=&maxobs
|
|
66
|
+
,random_sample=&random_sample
|
|
67
|
+
%if "&outfile" ne "0" %then %do;
|
|
68
|
+
,append=YES
|
|
69
|
+
,cards_file="&outloc/&outfile"
|
|
70
|
+
%end;
|
|
71
|
+
%else %do;
|
|
72
|
+
,append=NO
|
|
73
|
+
,cards_file="&outloc/&ds..sas"
|
|
74
|
+
%end;
|
|
75
|
+
)
|
|
76
|
+
%end;
|
|
77
|
+
|
|
78
|
+
%mend mp_lib2cards;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Convert all data in a library to SQL insert statements
|
|
4
|
+
@details Gets list of members then calls the <code>%mp_ds2inserts()</code>
|
|
5
|
+
macro.
|
|
6
|
+
Usage:
|
|
7
|
+
|
|
8
|
+
%mp_getddl(sashelp, schema=work, fref=tempref)
|
|
9
|
+
|
|
10
|
+
%mp_lib2inserts(sashelp, schema=work, outref=tempref)
|
|
11
|
+
|
|
12
|
+
%inc tempref;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
The output will be one file in the outref fileref.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<h4> SAS Macros </h4>
|
|
19
|
+
@li mp_ds2inserts.sas
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@param [in] lib Library in which to convert all datasets to inserts
|
|
23
|
+
@param [in] flavour= (SAS) The SQL flavour to be applied to the output. Valid
|
|
24
|
+
options:
|
|
25
|
+
@li SAS (default) - suitable for regular proc sql
|
|
26
|
+
@li PGSQL - Used for Postgres databases
|
|
27
|
+
@param [in] maxobs= (max) The max number of observations (per table) to create
|
|
28
|
+
@param [out] outref= Output fileref in which to create the insert statements.
|
|
29
|
+
If it exists, it will be appended to, otherwise it will be created.
|
|
30
|
+
@param [out] schema= (0) The schema of the target database, or the libref.
|
|
31
|
+
@param [in] applydttm= (YES) If YES, any columns using datetime formats will
|
|
32
|
+
be converted to native DB datetime literals
|
|
33
|
+
|
|
34
|
+
@version 9.2
|
|
35
|
+
@author Allan Bowe
|
|
36
|
+
**/
|
|
37
|
+
|
|
38
|
+
%macro mp_lib2inserts(lib
|
|
39
|
+
,flavour=SAS
|
|
40
|
+
,outref=0
|
|
41
|
+
,schema=0
|
|
42
|
+
,maxobs=max
|
|
43
|
+
,applydttm=YES
|
|
44
|
+
)/*/STORE SOURCE*/;
|
|
45
|
+
|
|
46
|
+
/* Find the tables */
|
|
47
|
+
%local x ds memlist;
|
|
48
|
+
proc sql noprint;
|
|
49
|
+
select distinct lowcase(memname)
|
|
50
|
+
into: memlist
|
|
51
|
+
separated by ' '
|
|
52
|
+
from dictionary.tables
|
|
53
|
+
where upcase(libname)="%upcase(&lib)"
|
|
54
|
+
and memtype='DATA'; /* exclude views */
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
%let flavour=%upcase(&flavour);
|
|
58
|
+
%if &flavour ne SAS and &flavour ne PGSQL %then %do;
|
|
59
|
+
%put %str(WAR)NING: &flavour is not supported;
|
|
60
|
+
%return;
|
|
61
|
+
%end;
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/* create the inserts */
|
|
65
|
+
%do x=1 %to %sysfunc(countw(&memlist));
|
|
66
|
+
%let ds=%scan(&memlist,&x);
|
|
67
|
+
%mp_ds2inserts(&lib..&ds
|
|
68
|
+
,outref=&outref
|
|
69
|
+
,schema=&schema
|
|
70
|
+
,outds=&ds
|
|
71
|
+
,flavour=&flavour
|
|
72
|
+
,maxobs=&maxobs
|
|
73
|
+
,applydttm=&applydttm
|
|
74
|
+
)
|
|
75
|
+
%end;
|
|
76
|
+
|
|
77
|
+
%mend mp_lib2inserts;
|