mirror of
https://github.com/sasjs/core.git
synced 2026-01-10 02:40:05 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62837b512b | ||
|
|
5d5a99fd77 | ||
|
|
1b5effd584 | ||
|
|
1613ab2c9e | ||
|
|
a2df4e35be | ||
|
|
aabbcfdf6b | ||
|
|
7b7759e1ce | ||
|
|
e5a3053600 | ||
|
|
9856d0ef58 | ||
|
|
77b37e5503 | ||
|
|
793319fe38 |
18
README.md
18
README.md
@@ -36,21 +36,21 @@ Documentation: https://core.sasjs.io
|
|||||||
- OS independent
|
- OS independent
|
||||||
- Works on all SAS Platforms
|
- Works on all SAS Platforms
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _mf_, _mp_
|
- Prefixes: `mf_`, `mp_`
|
||||||
|
|
||||||
### DDL folder (All Platforms)
|
### DDL folder (All Platforms)
|
||||||
|
|
||||||
- OS independent
|
- OS independent
|
||||||
- Works on all SAS Platforms
|
- Works on all SAS Platforms
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _mddl_(lib)_ -> where lib can be "SAS" (in relation to a SAS component) or "DC" (in relation to a Data Controller component)
|
- Prefixes: `mddl_(lib)_` -> where lib can be "SAS" (in relation to a SAS component) or "DC" (in relation to a Data Controller component)
|
||||||
|
|
||||||
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
|
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
|
||||||
|
|
||||||
### FCMP folder (All Platforms)
|
### FCMP folder (All Platforms)
|
||||||
|
|
||||||
- Function and macro names are identical, except for special cases
|
- Function and macro names are identical, except for special cases
|
||||||
- Prefixes: _mcf_
|
- Prefixes: `mcf_`
|
||||||
|
|
||||||
The fcmp macros are used to generate fcmp functions, and can be used with or without the `proc fcmp` wrapper.
|
The fcmp macros are used to generate fcmp functions, and can be used with or without the `proc fcmp` wrapper.
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ endsubmit;
|
|||||||
run;
|
run;
|
||||||
```
|
```
|
||||||
|
|
||||||
- Prefixes: _ml_
|
- Prefixes: `ml_`
|
||||||
|
|
||||||
### META folder (SAS9 only)
|
### META folder (SAS9 only)
|
||||||
|
|
||||||
@@ -81,14 +81,14 @@ Macros used in SAS EBI, which connect to the metadata server.
|
|||||||
- OS independent
|
- OS independent
|
||||||
- Metadata aware
|
- Metadata aware
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _mm_
|
- Prefixes: `mm_`
|
||||||
|
|
||||||
### METAX folder (SAS9 only)
|
### METAX folder (SAS9 only)
|
||||||
|
|
||||||
- OS specific
|
- OS specific
|
||||||
- Metadata aware
|
- Metadata aware
|
||||||
- X command enabled
|
- X command enabled
|
||||||
- Prefixes: _mmw_,_mmu_,_mmx_
|
- Prefixes: `mmx_`
|
||||||
|
|
||||||
### SERVER folder (@sasjs/server only)
|
### SERVER folder (@sasjs/server only)
|
||||||
These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
|
These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
|
||||||
@@ -96,7 +96,7 @@ These macros are used for building applications using [@sasjs/server](https://se
|
|||||||
- OS independent
|
- OS independent
|
||||||
- @sasjs/server aware
|
- @sasjs/server aware
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _ms_
|
- Prefixes: `ms_`
|
||||||
|
|
||||||
### VIYA folder (Viya only)
|
### VIYA folder (Viya only)
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ Macros used for interfacing with SAS Viya.
|
|||||||
|
|
||||||
- OS independent
|
- OS independent
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _mv_, _mvf_
|
- Prefixes: `mv_`, `mvf_`
|
||||||
|
|
||||||
### XPLATFORM folder (Viya, Meta, and Server)
|
### XPLATFORM folder (Viya, Meta, and Server)
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ Sometimes it is helpful to use a macro that can be used interchangeably regardle
|
|||||||
|
|
||||||
- OS independent
|
- OS independent
|
||||||
- No X command
|
- No X command
|
||||||
- Prefixes: _mx_
|
- Prefixes: `mx_`
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
||||||
that should be converted to JSON
|
that should be converted to JSON
|
||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Files </h4>
|
||||||
@li mp_ds2fmtds.sas
|
@li mp_ds2fmtds.sas
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@@ -76,7 +76,8 @@
|
|||||||
,showmeta=N
|
,showmeta=N
|
||||||
,maxobs=MAX
|
,maxobs=MAX
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval;
|
%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval
|
||||||
|
tmpds1 tmpds2 tmpds3 tmpds4;
|
||||||
%let numcols=0;
|
%let numcols=0;
|
||||||
%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;);
|
%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;);
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@
|
|||||||
by varnum;
|
by varnum;
|
||||||
run;
|
run;
|
||||||
/* move meta to mac vars */
|
/* move meta to mac vars */
|
||||||
data _null_;
|
data &colinfo;
|
||||||
if _n_=1 then call symputx('numcols',nobs,'l');
|
if _n_=1 then call symputx('numcols',nobs,'l');
|
||||||
set &colinfo end=last nobs=nobs;
|
set &colinfo end=last nobs=nobs;
|
||||||
name=upcase(name);
|
name=upcase(name);
|
||||||
@@ -135,18 +136,17 @@
|
|||||||
end;
|
end;
|
||||||
/* 32 char unique name */
|
/* 32 char unique name */
|
||||||
newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27);
|
newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27);
|
||||||
maxlenv='maxlen'!!substr(cats(put(md5(name),$hex32.)),1,26);
|
|
||||||
|
|
||||||
call symputx(cats('name',_n_),name,'l');
|
call symputx(cats('name',_n_),name,'l');
|
||||||
call symputx(cats('newname',_n_),newname,'l');
|
call symputx(cats('newname',_n_),newname,'l');
|
||||||
call symputx(cats('maxlenv',_n_),maxlenv,'l');
|
|
||||||
call symputx(cats('length',_n_),length,'l');
|
call symputx(cats('length',_n_),length,'l');
|
||||||
/* overwritten when fmt=Y */
|
|
||||||
call symputx(cats('fmtlen',_n_),min(32767,ceil((length+3)*1.2)),'l');
|
|
||||||
call symputx(cats('fmt',_n_),fmt,'l');
|
call symputx(cats('fmt',_n_),fmt,'l');
|
||||||
call symputx(cats('type',_n_),type,'l');
|
call symputx(cats('type',_n_),type,'l');
|
||||||
call symputx(cats('typelong',_n_),typelong,'l');
|
call symputx(cats('typelong',_n_),typelong,'l');
|
||||||
call symputx(cats('label',_n_),coalescec(label,name),'l');
|
call symputx(cats('label',_n_),coalescec(label,name),'l');
|
||||||
|
/* overwritten when fmt=Y and a custom format exists in catalog */
|
||||||
|
if typelong='num' then call symputx(cats('fmtlen',_n_),200,'l');
|
||||||
|
else call symputx(cats('fmtlen',_n_),min(32767,ceil((length+3)*1.5)),'l');
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
||||||
@@ -189,30 +189,82 @@
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &fmt=Y %then %do;
|
%if &fmt=Y %then %do;
|
||||||
%let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
/**
|
||||||
/* need to find max length of formatted values */
|
* Extract format definitions
|
||||||
|
* First, by getting library locations from dictionary.formats
|
||||||
|
* Then, by exporting the width using proc format
|
||||||
|
* Cannot use maxw from sashelp.vformat as not always populated
|
||||||
|
* Cannot use fmtinfo() as not supported in all flavours
|
||||||
|
*/
|
||||||
|
%let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
||||||
|
%let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
||||||
|
%let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
||||||
|
%let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
|
||||||
|
proc sql noprint;
|
||||||
|
create table &tmpds1 as
|
||||||
|
select cats(libname,'.',memname) as fmtcat,
|
||||||
|
fmtname
|
||||||
|
from dictionary.formats
|
||||||
|
where fmttype='F' and libname is not null
|
||||||
|
and fmtname in (select format from &colinfo where format is not null)
|
||||||
|
order by 1;
|
||||||
|
create table &tmpds2(
|
||||||
|
FMTNAME char(32),
|
||||||
|
LENGTH num
|
||||||
|
);
|
||||||
|
%local catlist cat fmtlist i;
|
||||||
|
select distinct fmtcat into: catlist separated by ' ' from &tmpds1;
|
||||||
|
%do i=1 %to %sysfunc(countw(&catlist,%str( )));
|
||||||
|
%let cat=%scan(&catlist,&i,%str( ));
|
||||||
|
proc sql;
|
||||||
|
select distinct fmtname into: fmtlist separated by ' '
|
||||||
|
from &tmpds1 where fmtcat="&cat";
|
||||||
|
proc format lib=&cat cntlout=&tmpds3(keep=fmtname length);
|
||||||
|
select &fmtlist;
|
||||||
|
run;
|
||||||
|
proc sql;
|
||||||
|
insert into &tmpds2 select distinct fmtname,length from &tmpds3;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
create table &tmpds4 as
|
||||||
|
select a.*, b.length as maxw
|
||||||
|
from &colinfo a
|
||||||
|
left join &tmpds2 b
|
||||||
|
on cats(a.format)=cats(upcase(b.fmtname))
|
||||||
|
order by a.varnum;
|
||||||
|
data _null_;
|
||||||
|
set &tmpds4;
|
||||||
|
if not missing(maxw);
|
||||||
|
call symputx(
|
||||||
|
cats('fmtlen',_n_),
|
||||||
|
/* vars need extra padding due to JSON escaping of special chars */
|
||||||
|
min(32767,ceil((max(length,maxw)+3)*1.5))
|
||||||
|
,'l'
|
||||||
|
);
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* configure varlenchk - as we are explicitly shortening the variables */
|
||||||
|
%let optval=%sysfunc(getoption(varlenchk));
|
||||||
|
options varlenchk=NOWARN;
|
||||||
data _data_(compress=char);
|
data _data_(compress=char);
|
||||||
|
/* shorten the new vars */
|
||||||
|
length
|
||||||
|
%do i=1 %to &numcols;
|
||||||
|
&&name&i $&&fmtlen&i
|
||||||
|
%end;
|
||||||
|
;
|
||||||
/* rename on entry */
|
/* rename on entry */
|
||||||
set &ds(rename=(
|
set &ds(rename=(
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
&&name&i=&&newname&i
|
&&name&i=&&newname&i
|
||||||
%end;
|
%end;
|
||||||
));
|
));
|
||||||
&stmt_obs;
|
&stmt_obs;
|
||||||
/* formatted values can be up to length 32767 */
|
|
||||||
length
|
drop
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
&&name&i
|
&&newname&i
|
||||||
%end;
|
|
||||||
$32767;
|
|
||||||
retain &tempvar
|
|
||||||
%do i=1 %to &numcols;
|
|
||||||
&&maxlenv&i
|
|
||||||
%end;
|
|
||||||
0;
|
|
||||||
drop &tempvar
|
|
||||||
%do i=1 %to &numcols;
|
|
||||||
&&newname&i &&maxlenv&i
|
|
||||||
%end;
|
%end;
|
||||||
;
|
;
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
@@ -222,19 +274,14 @@
|
|||||||
%else %do;
|
%else %do;
|
||||||
&&name&i=put(&&newname&i,&&fmt&i);
|
&&name&i=put(&&newname&i,&&fmt&i);
|
||||||
%end;
|
%end;
|
||||||
/* grab max length of each value as we move down the data step */
|
|
||||||
&tempvar=length(&&name&i);
|
|
||||||
if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar;
|
|
||||||
%end;
|
|
||||||
if _n_=&lastobs then do;
|
|
||||||
/* add a 20% buffer in case of special chars that need to be escaped */
|
|
||||||
%do i=1 %to &numcols;
|
|
||||||
call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),'l');
|
|
||||||
%end;
|
%end;
|
||||||
|
if _error_ then do;
|
||||||
|
call symputx('syscc',1012);
|
||||||
|
stop;
|
||||||
end;
|
end;
|
||||||
if _error_ then call symputx('syscc',1012);
|
|
||||||
run;
|
run;
|
||||||
%let fmtds=&syslast;
|
%let fmtds=&syslast;
|
||||||
|
options varlenchk=&optval;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
proc format; /* credit yabwon for special null removal */
|
proc format; /* credit yabwon for special null removal */
|
||||||
@@ -249,9 +296,6 @@
|
|||||||
%end;
|
%end;
|
||||||
other = [best.];
|
other = [best.];
|
||||||
|
|
||||||
/* configure varlenchk - as we are explicitly shortening the variables */
|
|
||||||
%let optval=%sysfunc(getoption(varlenchk));
|
|
||||||
options varlenchk=NOWARN;
|
|
||||||
data &tempds;
|
data &tempds;
|
||||||
attrib _all_ label='';
|
attrib _all_ label='';
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
@@ -290,7 +334,6 @@
|
|||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
run;
|
run;
|
||||||
options varlenchk=&optval;
|
|
||||||
|
|
||||||
filename _sjs3 temp lrecl=131068 ;
|
filename _sjs3 temp lrecl=131068 ;
|
||||||
data _null_;
|
data _null_;
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ data _null_;
|
|||||||
put ' ,showmeta=N ';
|
put ' ,showmeta=N ';
|
||||||
put ' ,maxobs=MAX ';
|
put ' ,maxobs=MAX ';
|
||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
|
put '%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval ';
|
||||||
|
put ' tmpds1 tmpds2 tmpds3 tmpds4; ';
|
||||||
put '%let numcols=0; ';
|
put '%let numcols=0; ';
|
||||||
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
||||||
put ' ';
|
put ' ';
|
||||||
@@ -137,7 +138,7 @@ data _null_;
|
|||||||
put ' by varnum; ';
|
put ' by varnum; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' /* move meta to mac vars */ ';
|
put ' /* move meta to mac vars */ ';
|
||||||
put ' data _null_; ';
|
put ' data &colinfo; ';
|
||||||
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
||||||
put ' set &colinfo end=last nobs=nobs; ';
|
put ' set &colinfo end=last nobs=nobs; ';
|
||||||
put ' name=upcase(name); ';
|
put ' name=upcase(name); ';
|
||||||
@@ -158,18 +159,17 @@ data _null_;
|
|||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' /* 32 char unique name */ ';
|
put ' /* 32 char unique name */ ';
|
||||||
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
||||||
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
||||||
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
||||||
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
|
|
||||||
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
||||||
put ' /* overwritten when fmt=Y */ ';
|
|
||||||
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
|
|
||||||
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
||||||
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
||||||
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
||||||
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
||||||
|
put ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
|
||||||
|
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); ';
|
||||||
|
put ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.5)),''l''); ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
@@ -212,30 +212,82 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %if &fmt=Y %then %do; ';
|
put ' %if &fmt=Y %then %do; ';
|
||||||
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' /** ';
|
||||||
put ' /* need to find max length of formatted values */ ';
|
put ' * Extract format definitions ';
|
||||||
|
put ' * First, by getting library locations from dictionary.formats ';
|
||||||
|
put ' * Then, by exporting the width using proc format ';
|
||||||
|
put ' * Cannot use maxw from sashelp.vformat as not always populated ';
|
||||||
|
put ' * Cannot use fmtinfo() as not supported in all flavours ';
|
||||||
|
put ' */ ';
|
||||||
|
put ' %let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' proc sql noprint; ';
|
||||||
|
put ' create table &tmpds1 as ';
|
||||||
|
put ' select cats(libname,''.'',memname) as fmtcat, ';
|
||||||
|
put ' fmtname ';
|
||||||
|
put ' from dictionary.formats ';
|
||||||
|
put ' where fmttype=''F'' and libname is not null ';
|
||||||
|
put ' and fmtname in (select format from &colinfo where format is not null) ';
|
||||||
|
put ' order by 1; ';
|
||||||
|
put ' create table &tmpds2( ';
|
||||||
|
put ' FMTNAME char(32), ';
|
||||||
|
put ' LENGTH num ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' %local catlist cat fmtlist i; ';
|
||||||
|
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
|
||||||
|
put ' %do i=1 %to %sysfunc(countw(&catlist,%str( ))); ';
|
||||||
|
put ' %let cat=%scan(&catlist,&i,%str( )); ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' select distinct fmtname into: fmtlist separated by '' '' ';
|
||||||
|
put ' from &tmpds1 where fmtcat="&cat"; ';
|
||||||
|
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
|
||||||
|
put ' select &fmtlist; ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' create table &tmpds4 as ';
|
||||||
|
put ' select a.*, b.length as maxw ';
|
||||||
|
put ' from &colinfo a ';
|
||||||
|
put ' left join &tmpds2 b ';
|
||||||
|
put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
|
||||||
|
put ' order by a.varnum; ';
|
||||||
|
put ' data _null_; ';
|
||||||
|
put ' set &tmpds4; ';
|
||||||
|
put ' if not missing(maxw); ';
|
||||||
|
put ' call symputx( ';
|
||||||
|
put ' cats(''fmtlen'',_n_), ';
|
||||||
|
put ' /* vars need extra padding due to JSON escaping of special chars */ ';
|
||||||
|
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) ';
|
||||||
|
put ' ,''l'' ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' ';
|
||||||
|
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
||||||
|
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
||||||
|
put ' options varlenchk=NOWARN; ';
|
||||||
put ' data _data_(compress=char); ';
|
put ' data _data_(compress=char); ';
|
||||||
|
put ' /* shorten the new vars */ ';
|
||||||
|
put ' length ';
|
||||||
|
put ' %do i=1 %to &numcols; ';
|
||||||
|
put ' &&name&i $&&fmtlen&i ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ; ';
|
||||||
put ' /* rename on entry */ ';
|
put ' /* rename on entry */ ';
|
||||||
put ' set &ds(rename=( ';
|
put ' set &ds(rename=( ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i=&&newname&i ';
|
put ' &&name&i=&&newname&i ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' )); ';
|
put ' )); ';
|
||||||
put ' &stmt_obs; ';
|
put ' &stmt_obs; ';
|
||||||
put ' /* formatted values can be up to length 32767 */ ';
|
put ' ';
|
||||||
put ' length ';
|
put ' drop ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i ';
|
put ' &&newname&i ';
|
||||||
put ' %end; ';
|
|
||||||
put ' $32767; ';
|
|
||||||
put ' retain &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' 0; ';
|
|
||||||
put ' drop &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&newname&i &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ; ';
|
put ' ; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -245,19 +297,14 @@ data _null_;
|
|||||||
put ' %else %do; ';
|
put ' %else %do; ';
|
||||||
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' /* grab max length of each value as we move down the data step */ ';
|
|
||||||
put ' &tempvar=length(&&name&i); ';
|
|
||||||
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' if _n_=&lastobs then do; ';
|
|
||||||
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
put ' if _error_ then do; ';
|
||||||
|
put ' call symputx(''syscc'',1012); ';
|
||||||
|
put ' stop; ';
|
||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' %let fmtds=&syslast; ';
|
put ' %let fmtds=&syslast; ';
|
||||||
|
put ' options varlenchk=&optval; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' proc format; /* credit yabwon for special null removal */ ';
|
put ' proc format; /* credit yabwon for special null removal */ ';
|
||||||
@@ -272,9 +319,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' other = [best.]; ';
|
put ' other = [best.]; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
|
||||||
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
|
||||||
put ' options varlenchk=NOWARN; ';
|
|
||||||
put ' data &tempds; ';
|
put ' data &tempds; ';
|
||||||
put ' attrib _all_ label=''''; ';
|
put ' attrib _all_ label=''''; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -313,7 +357,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' options varlenchk=&optval; ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' filename _sjs3 temp lrecl=131068 ; ';
|
put ' filename _sjs3 temp lrecl=131068 ; ';
|
||||||
put ' data _null_; ';
|
put ' data _null_; ';
|
||||||
@@ -403,8 +446,8 @@ data _null_;
|
|||||||
put ' %quote(&user) ';
|
put ' %quote(&user) ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put '%mend mf_getuser; ';
|
put '%mend mf_getuser; ';
|
||||||
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
|
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL ';
|
||||||
put ' ,showmeta=N,maxobs=MAX ';
|
put ' ,showmeta=N,maxobs=MAX,workobs=0 ';
|
||||||
put '); ';
|
put '); ';
|
||||||
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
|
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
|
||||||
put ' sasjs_tables; ';
|
put ' sasjs_tables; ';
|
||||||
@@ -477,8 +520,8 @@ data _null_;
|
|||||||
put '%else %if &action=CLOSE %then %do; ';
|
put '%else %if &action=CLOSE %then %do; ';
|
||||||
put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
|
put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
|
||||||
put ' filename _sjsref temp lrecl=131068; ';
|
put ' filename _sjsref temp lrecl=131068; ';
|
||||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
put ' %if %str(&workobs) > 0 %then %do; ';
|
||||||
put ' /* if debug mode, send back first 10 records of each work table also */ ';
|
put ' /* if debug mode, send back first XX records of each work table also */ ';
|
||||||
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
||||||
put ' ods output Members=&tempds; ';
|
put ' ods output Members=&tempds; ';
|
||||||
put ' proc datasets library=WORK memtype=data; ';
|
put ' proc datasets library=WORK memtype=data; ';
|
||||||
@@ -502,7 +545,9 @@ data _null_;
|
|||||||
put ' put " ""&wt"" : {"; ';
|
put ' put " ""&wt"" : {"; ';
|
||||||
put ' put ''"nlobs":'' nlobs; ';
|
put ' put ''"nlobs":'' nlobs; ';
|
||||||
put ' put '',"nvars":'' nvars; ';
|
put ' put '',"nvars":'' nvars; ';
|
||||||
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10) ';
|
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
|
||||||
|
put ' ,maxobs=&workobs ';
|
||||||
|
put ' ) ';
|
||||||
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
|
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
|
||||||
put ' put "}"; ';
|
put ' put "}"; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
|||||||
67
meta/mm_getstpinfo.sas
Normal file
67
meta/mm_getstpinfo.sas
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Get the properties of a Stored Process
|
||||||
|
@details Extracts various properties and creates an output table in the
|
||||||
|
structure below:
|
||||||
|
|
||||||
|
|STP_URI:$200.|SERVERCONTEXT:$200.|STOREDPROCESSCONFIGURATION:$1000.|SOURCECODE_FIRST32K:$32767.|PATH:$76.|
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|`A5DN9TDQ.BH0000C8 `|`SASApp `|`<?xml version="1.0" encoding="UTF-8"?><StoredProcess><ServerContext LogicalServerType="Sps" OtherAllowed="false"/><ResultCapabilities Package="false" Streaming="true"/><OutputParameters/></StoredProcess> `|`%put first 32767 bytes of code; `|`/path/to/my/stp`|
|
||||||
|
|
||||||
|
@param [in] pgm The metadata path of the Stored Process
|
||||||
|
@param [out] outds= (work.mm_getstpinfo) The output table to create
|
||||||
|
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||||
|
|
||||||
|
<h4> Related Files </h4>
|
||||||
|
@li mm_getstpcode.sas
|
||||||
|
@li mm_getstps.sas
|
||||||
|
@li mm_createstp.sas
|
||||||
|
@li mm_deletestp.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mm_getstpinfo(pgm
|
||||||
|
,outds=work.mm_getstpinfo
|
||||||
|
,mDebug=0
|
||||||
|
);
|
||||||
|
|
||||||
|
%local mD;
|
||||||
|
%if &mDebug=1 %then %let mD=;
|
||||||
|
%else %let mD=%str(*);
|
||||||
|
%&mD.put Executing &sysmacroname..sas;
|
||||||
|
%&mD.put _local_;
|
||||||
|
|
||||||
|
data &outds;
|
||||||
|
length type stp_uri tsuri servercontext value $200
|
||||||
|
StoredProcessConfiguration $1000 sourcecode_first32k $32767;
|
||||||
|
keep path stp_uri sourcecode_first32k StoredProcessConfiguration
|
||||||
|
servercontext;
|
||||||
|
call missing (of _all_);
|
||||||
|
path="&pgm(StoredProcess)";
|
||||||
|
/* first, find the STP ID */
|
||||||
|
if metadata_pathobj("",path,"StoredProcess",type,stp_uri)>0 then do;
|
||||||
|
/* get attributes */
|
||||||
|
cnt=1;
|
||||||
|
do while (metadata_getnasn(stp_uri,"Notes",cnt,tsuri)>0);
|
||||||
|
rc1=metadata_getattr(tsuri,"Name",value);
|
||||||
|
&mD.put tsuri= value=;
|
||||||
|
if value="SourceCode" then do;
|
||||||
|
rc2=metadata_getattr(tsuri,"StoredText",sourcecode_first32k);
|
||||||
|
end;
|
||||||
|
else if value="Stored Process" then do;
|
||||||
|
rc3=metadata_getattr(tsuri,"StoredText",StoredProcessConfiguration);
|
||||||
|
end;
|
||||||
|
cnt+1;
|
||||||
|
end;
|
||||||
|
/* get context (should only be one) */
|
||||||
|
rc4=metadata_getnasn(stp_uri,"ComputeLocations",1,tsuri);
|
||||||
|
rc5=metadata_getattr(tsuri,"Name",servercontext);
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
put "%str(ERR)OR: could not find " pgm;
|
||||||
|
put (_all_)(=);
|
||||||
|
end;
|
||||||
|
&md.put (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mend mm_getstpinfo ;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
|
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
|
||||||
@param [in] ds The dataset to send back to the frontend
|
@param [in] ds The dataset to send back to the frontend
|
||||||
@param [out] dslabel= Value to use instead of table name for sending to JSON
|
@param [out] dslabel= Value to use instead of table name for sending to JSON
|
||||||
@param [in] fmt=(Y) Set to N to send back unformatted values
|
@param [in] fmt= (N) Setting Y converts all vars to their formatted values
|
||||||
@param [out] fref= (_webout) The fileref to which to write the JSON
|
@param [out] fref= (_webout) The fileref to which to write the JSON
|
||||||
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
||||||
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
||||||
@@ -34,18 +34,25 @@
|
|||||||
such as the column formats and types. The metadata is contained inside an
|
such as the column formats and types. The metadata is contained inside an
|
||||||
object with the same name as the table but prefixed with a dollar sign - ie,
|
object with the same name as the table but prefixed with a dollar sign - ie,
|
||||||
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
||||||
|
@param [in] workobs= (0) When set to a positive integer, will create a new
|
||||||
|
output object (WORK) which contains this number of observations from all
|
||||||
|
tables in the WORK library.
|
||||||
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
||||||
that should be converted to output JSON
|
that should be converted to output JSON
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_jsonout.sas
|
@li mp_jsonout.sas
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li ms_webout.sas
|
||||||
|
@li mv_webout.sas
|
||||||
|
|
||||||
@version 9.3
|
@version 9.3
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
**/
|
**/
|
||||||
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL
|
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL
|
||||||
,showmeta=N,maxobs=MAX
|
,showmeta=N,maxobs=MAX,workobs=0
|
||||||
);
|
);
|
||||||
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
|
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
|
||||||
sasjs_tables;
|
sasjs_tables;
|
||||||
@@ -118,8 +125,8 @@
|
|||||||
%else %if &action=CLOSE %then %do;
|
%else %if &action=CLOSE %then %do;
|
||||||
/* To avoid issues with _webout on EBI we use a temporary file */
|
/* To avoid issues with _webout on EBI we use a temporary file */
|
||||||
filename _sjsref temp lrecl=131068;
|
filename _sjsref temp lrecl=131068;
|
||||||
%if %str(&_debug) ge 131 %then %do;
|
%if %str(&workobs) > 0 %then %do;
|
||||||
/* if debug mode, send back first 10 records of each work table also */
|
/* if debug mode, send back first XX records of each work table also */
|
||||||
data;run;%let tempds=%scan(&syslast,2,.);
|
data;run;%let tempds=%scan(&syslast,2,.);
|
||||||
ods output Members=&tempds;
|
ods output Members=&tempds;
|
||||||
proc datasets library=WORK memtype=data;
|
proc datasets library=WORK memtype=data;
|
||||||
@@ -143,7 +150,9 @@
|
|||||||
put " ""&wt"" : {";
|
put " ""&wt"" : {";
|
||||||
put '"nlobs":' nlobs;
|
put '"nlobs":' nlobs;
|
||||||
put ',"nvars":' nvars;
|
put ',"nvars":' nvars;
|
||||||
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10)
|
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10
|
||||||
|
,maxobs=&workobs
|
||||||
|
)
|
||||||
data _null_; file _sjsref mod encoding='utf-8';
|
data _null_; file _sjsref mod encoding='utf-8';
|
||||||
put "}";
|
put "}";
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ data _null_;
|
|||||||
put ' ,showmeta=N ';
|
put ' ,showmeta=N ';
|
||||||
put ' ,maxobs=MAX ';
|
put ' ,maxobs=MAX ';
|
||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
|
put '%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval ';
|
||||||
|
put ' tmpds1 tmpds2 tmpds3 tmpds4; ';
|
||||||
put '%let numcols=0; ';
|
put '%let numcols=0; ';
|
||||||
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
||||||
put ' ';
|
put ' ';
|
||||||
@@ -138,7 +139,7 @@ data _null_;
|
|||||||
put ' by varnum; ';
|
put ' by varnum; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' /* move meta to mac vars */ ';
|
put ' /* move meta to mac vars */ ';
|
||||||
put ' data _null_; ';
|
put ' data &colinfo; ';
|
||||||
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
||||||
put ' set &colinfo end=last nobs=nobs; ';
|
put ' set &colinfo end=last nobs=nobs; ';
|
||||||
put ' name=upcase(name); ';
|
put ' name=upcase(name); ';
|
||||||
@@ -159,18 +160,17 @@ data _null_;
|
|||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' /* 32 char unique name */ ';
|
put ' /* 32 char unique name */ ';
|
||||||
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
||||||
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
||||||
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
||||||
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
|
|
||||||
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
||||||
put ' /* overwritten when fmt=Y */ ';
|
|
||||||
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
|
|
||||||
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
||||||
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
||||||
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
||||||
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
||||||
|
put ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
|
||||||
|
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); ';
|
||||||
|
put ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.5)),''l''); ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
@@ -213,30 +213,82 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %if &fmt=Y %then %do; ';
|
put ' %if &fmt=Y %then %do; ';
|
||||||
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' /** ';
|
||||||
put ' /* need to find max length of formatted values */ ';
|
put ' * Extract format definitions ';
|
||||||
|
put ' * First, by getting library locations from dictionary.formats ';
|
||||||
|
put ' * Then, by exporting the width using proc format ';
|
||||||
|
put ' * Cannot use maxw from sashelp.vformat as not always populated ';
|
||||||
|
put ' * Cannot use fmtinfo() as not supported in all flavours ';
|
||||||
|
put ' */ ';
|
||||||
|
put ' %let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' proc sql noprint; ';
|
||||||
|
put ' create table &tmpds1 as ';
|
||||||
|
put ' select cats(libname,''.'',memname) as fmtcat, ';
|
||||||
|
put ' fmtname ';
|
||||||
|
put ' from dictionary.formats ';
|
||||||
|
put ' where fmttype=''F'' and libname is not null ';
|
||||||
|
put ' and fmtname in (select format from &colinfo where format is not null) ';
|
||||||
|
put ' order by 1; ';
|
||||||
|
put ' create table &tmpds2( ';
|
||||||
|
put ' FMTNAME char(32), ';
|
||||||
|
put ' LENGTH num ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' %local catlist cat fmtlist i; ';
|
||||||
|
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
|
||||||
|
put ' %do i=1 %to %sysfunc(countw(&catlist,%str( ))); ';
|
||||||
|
put ' %let cat=%scan(&catlist,&i,%str( )); ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' select distinct fmtname into: fmtlist separated by '' '' ';
|
||||||
|
put ' from &tmpds1 where fmtcat="&cat"; ';
|
||||||
|
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
|
||||||
|
put ' select &fmtlist; ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' create table &tmpds4 as ';
|
||||||
|
put ' select a.*, b.length as maxw ';
|
||||||
|
put ' from &colinfo a ';
|
||||||
|
put ' left join &tmpds2 b ';
|
||||||
|
put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
|
||||||
|
put ' order by a.varnum; ';
|
||||||
|
put ' data _null_; ';
|
||||||
|
put ' set &tmpds4; ';
|
||||||
|
put ' if not missing(maxw); ';
|
||||||
|
put ' call symputx( ';
|
||||||
|
put ' cats(''fmtlen'',_n_), ';
|
||||||
|
put ' /* vars need extra padding due to JSON escaping of special chars */ ';
|
||||||
|
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) ';
|
||||||
|
put ' ,''l'' ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' ';
|
||||||
|
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
||||||
|
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
||||||
|
put ' options varlenchk=NOWARN; ';
|
||||||
put ' data _data_(compress=char); ';
|
put ' data _data_(compress=char); ';
|
||||||
|
put ' /* shorten the new vars */ ';
|
||||||
|
put ' length ';
|
||||||
|
put ' %do i=1 %to &numcols; ';
|
||||||
|
put ' &&name&i $&&fmtlen&i ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ; ';
|
||||||
put ' /* rename on entry */ ';
|
put ' /* rename on entry */ ';
|
||||||
put ' set &ds(rename=( ';
|
put ' set &ds(rename=( ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i=&&newname&i ';
|
put ' &&name&i=&&newname&i ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' )); ';
|
put ' )); ';
|
||||||
put ' &stmt_obs; ';
|
put ' &stmt_obs; ';
|
||||||
put ' /* formatted values can be up to length 32767 */ ';
|
put ' ';
|
||||||
put ' length ';
|
put ' drop ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i ';
|
put ' &&newname&i ';
|
||||||
put ' %end; ';
|
|
||||||
put ' $32767; ';
|
|
||||||
put ' retain &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' 0; ';
|
|
||||||
put ' drop &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&newname&i &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ; ';
|
put ' ; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -246,19 +298,14 @@ data _null_;
|
|||||||
put ' %else %do; ';
|
put ' %else %do; ';
|
||||||
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' /* grab max length of each value as we move down the data step */ ';
|
|
||||||
put ' &tempvar=length(&&name&i); ';
|
|
||||||
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' if _n_=&lastobs then do; ';
|
|
||||||
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
put ' if _error_ then do; ';
|
||||||
|
put ' call symputx(''syscc'',1012); ';
|
||||||
|
put ' stop; ';
|
||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' %let fmtds=&syslast; ';
|
put ' %let fmtds=&syslast; ';
|
||||||
|
put ' options varlenchk=&optval; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' proc format; /* credit yabwon for special null removal */ ';
|
put ' proc format; /* credit yabwon for special null removal */ ';
|
||||||
@@ -273,9 +320,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' other = [best.]; ';
|
put ' other = [best.]; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
|
||||||
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
|
||||||
put ' options varlenchk=NOWARN; ';
|
|
||||||
put ' data &tempds; ';
|
put ' data &tempds; ';
|
||||||
put ' attrib _all_ label=''''; ';
|
put ' attrib _all_ label=''''; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -314,7 +358,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' options varlenchk=&optval; ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' filename _sjs3 temp lrecl=131068 ; ';
|
put ' filename _sjs3 temp lrecl=131068 ; ';
|
||||||
put ' data _null_; ';
|
put ' data _null_; ';
|
||||||
@@ -405,8 +448,8 @@ data _null_;
|
|||||||
put ' ';
|
put ' ';
|
||||||
put '%mend mf_getuser; ';
|
put '%mend mf_getuser; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
|
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL ';
|
||||||
put ' ,showmeta=N,maxobs=MAX ';
|
put ' ,showmeta=N,maxobs=MAX,workobs=0 ';
|
||||||
put '); ';
|
put '); ';
|
||||||
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
|
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
|
||||||
put ' sasjs_tables; ';
|
put ' sasjs_tables; ';
|
||||||
@@ -469,8 +512,8 @@ data _null_;
|
|||||||
put ' ) ';
|
put ' ) ';
|
||||||
put '%end; ';
|
put '%end; ';
|
||||||
put '%else %if &action=CLOSE %then %do; ';
|
put '%else %if &action=CLOSE %then %do; ';
|
||||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
put ' %if %str(&workobs) > 0 %then %do; ';
|
||||||
put ' /* if debug mode, send back first 10 records of each work table also */ ';
|
put ' /* if debug mode, send back first XX records of each work table also */ ';
|
||||||
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
||||||
put ' ods output Members=&tempds; ';
|
put ' ods output Members=&tempds; ';
|
||||||
put ' proc datasets library=WORK memtype=data; ';
|
put ' proc datasets library=WORK memtype=data; ';
|
||||||
@@ -495,7 +538,9 @@ data _null_;
|
|||||||
put ' put " ""&wt"" : {"; ';
|
put ' put " ""&wt"" : {"; ';
|
||||||
put ' put ''"nlobs":'' nlobs; ';
|
put ' put ''"nlobs":'' nlobs; ';
|
||||||
put ' put '',"nvars":'' nvars; ';
|
put ' put '',"nvars":'' nvars; ';
|
||||||
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10) ';
|
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
|
||||||
|
put ' ,maxobs=&workobs ';
|
||||||
|
put ' ) ';
|
||||||
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
||||||
put ' put "}"; ';
|
put ' put "}"; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
|
@param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
|
||||||
@param [in] ds The dataset to send back to the frontend
|
@param [in] ds The dataset to send back to the frontend
|
||||||
@param [out] dslabel= value to use instead of table name for sending to JSON
|
@param [out] dslabel= value to use instead of table name for sending to JSON
|
||||||
@param [in] fmt= (Y) Set to N to send back unformatted values
|
@param [in] fmt= (N) Setting Y converts all vars to their formatted values
|
||||||
@param [out] fref= (_webout) The fileref to which to write the JSON
|
@param [out] fref= (_webout) The fileref to which to write the JSON
|
||||||
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
||||||
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
||||||
@@ -31,6 +31,9 @@
|
|||||||
such as the column formats and types. The metadata is contained inside an
|
such as the column formats and types. The metadata is contained inside an
|
||||||
object with the same name as the table but prefixed with a dollar sign - ie,
|
object with the same name as the table but prefixed with a dollar sign - ie,
|
||||||
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
||||||
|
@param [in] workobs= (0) When set to a positive integer, will create a new
|
||||||
|
output object (WORK) which contains this number of observations from all
|
||||||
|
tables in the WORK library.
|
||||||
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
||||||
that should be converted to output JSON
|
that should be converted to output JSON
|
||||||
|
|
||||||
@@ -48,8 +51,8 @@
|
|||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL
|
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,missing=NULL
|
||||||
,showmeta=N,maxobs=MAX
|
,showmeta=N,maxobs=MAX,workobs=0
|
||||||
);
|
);
|
||||||
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
|
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
|
||||||
sasjs_tables;
|
sasjs_tables;
|
||||||
@@ -112,8 +115,8 @@
|
|||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%else %if &action=CLOSE %then %do;
|
%else %if &action=CLOSE %then %do;
|
||||||
%if %str(&_debug) ge 131 %then %do;
|
%if %str(&workobs) > 0 %then %do;
|
||||||
/* if debug mode, send back first 10 records of each work table also */
|
/* if debug mode, send back first XX records of each work table also */
|
||||||
data;run;%let tempds=%scan(&syslast,2,.);
|
data;run;%let tempds=%scan(&syslast,2,.);
|
||||||
ods output Members=&tempds;
|
ods output Members=&tempds;
|
||||||
proc datasets library=WORK memtype=data;
|
proc datasets library=WORK memtype=data;
|
||||||
@@ -138,7 +141,9 @@
|
|||||||
put " ""&wt"" : {";
|
put " ""&wt"" : {";
|
||||||
put '"nlobs":' nlobs;
|
put '"nlobs":' nlobs;
|
||||||
put ',"nvars":' nvars;
|
put ',"nvars":' nvars;
|
||||||
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10)
|
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10
|
||||||
|
,maxobs=&workobs
|
||||||
|
)
|
||||||
data _null_; file &fref mod encoding='utf-8' termstr=lf;
|
data _null_; file &fref mod encoding='utf-8' termstr=lf;
|
||||||
put "}";
|
put "}";
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -242,7 +242,8 @@ data _null_;
|
|||||||
put ' ,showmeta=N ';
|
put ' ,showmeta=N ';
|
||||||
put ' ,maxobs=MAX ';
|
put ' ,maxobs=MAX ';
|
||||||
put ')/*/STORE SOURCE*/; ';
|
put ')/*/STORE SOURCE*/; ';
|
||||||
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
|
put '%local tempds colinfo fmtds i numcols numobs stmt_obs lastobs optval ';
|
||||||
|
put ' tmpds1 tmpds2 tmpds3 tmpds4; ';
|
||||||
put '%let numcols=0; ';
|
put '%let numcols=0; ';
|
||||||
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
|
||||||
put ' ';
|
put ' ';
|
||||||
@@ -280,7 +281,7 @@ data _null_;
|
|||||||
put ' by varnum; ';
|
put ' by varnum; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' /* move meta to mac vars */ ';
|
put ' /* move meta to mac vars */ ';
|
||||||
put ' data _null_; ';
|
put ' data &colinfo; ';
|
||||||
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
||||||
put ' set &colinfo end=last nobs=nobs; ';
|
put ' set &colinfo end=last nobs=nobs; ';
|
||||||
put ' name=upcase(name); ';
|
put ' name=upcase(name); ';
|
||||||
@@ -301,18 +302,17 @@ data _null_;
|
|||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' /* 32 char unique name */ ';
|
put ' /* 32 char unique name */ ';
|
||||||
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
||||||
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
||||||
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
||||||
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
|
|
||||||
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
||||||
put ' /* overwritten when fmt=Y */ ';
|
|
||||||
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
|
|
||||||
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
||||||
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
||||||
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
||||||
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
||||||
|
put ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
|
||||||
|
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); ';
|
||||||
|
put ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.5)),''l''); ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
@@ -355,30 +355,82 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %if &fmt=Y %then %do; ';
|
put ' %if &fmt=Y %then %do; ';
|
||||||
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
put ' /** ';
|
||||||
put ' /* need to find max length of formatted values */ ';
|
put ' * Extract format definitions ';
|
||||||
|
put ' * First, by getting library locations from dictionary.formats ';
|
||||||
|
put ' * Then, by exporting the width using proc format ';
|
||||||
|
put ' * Cannot use maxw from sashelp.vformat as not always populated ';
|
||||||
|
put ' * Cannot use fmtinfo() as not supported in all flavours ';
|
||||||
|
put ' */ ';
|
||||||
|
put ' %let tmpds1=%substr(fmtsum%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds2=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds3=%substr(cntl%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||||
|
put ' proc sql noprint; ';
|
||||||
|
put ' create table &tmpds1 as ';
|
||||||
|
put ' select cats(libname,''.'',memname) as fmtcat, ';
|
||||||
|
put ' fmtname ';
|
||||||
|
put ' from dictionary.formats ';
|
||||||
|
put ' where fmttype=''F'' and libname is not null ';
|
||||||
|
put ' and fmtname in (select format from &colinfo where format is not null) ';
|
||||||
|
put ' order by 1; ';
|
||||||
|
put ' create table &tmpds2( ';
|
||||||
|
put ' FMTNAME char(32), ';
|
||||||
|
put ' LENGTH num ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' %local catlist cat fmtlist i; ';
|
||||||
|
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
|
||||||
|
put ' %do i=1 %to %sysfunc(countw(&catlist,%str( ))); ';
|
||||||
|
put ' %let cat=%scan(&catlist,&i,%str( )); ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' select distinct fmtname into: fmtlist separated by '' '' ';
|
||||||
|
put ' from &tmpds1 where fmtcat="&cat"; ';
|
||||||
|
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
|
||||||
|
put ' select &fmtlist; ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ';
|
||||||
|
put ' proc sql; ';
|
||||||
|
put ' create table &tmpds4 as ';
|
||||||
|
put ' select a.*, b.length as maxw ';
|
||||||
|
put ' from &colinfo a ';
|
||||||
|
put ' left join &tmpds2 b ';
|
||||||
|
put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
|
||||||
|
put ' order by a.varnum; ';
|
||||||
|
put ' data _null_; ';
|
||||||
|
put ' set &tmpds4; ';
|
||||||
|
put ' if not missing(maxw); ';
|
||||||
|
put ' call symputx( ';
|
||||||
|
put ' cats(''fmtlen'',_n_), ';
|
||||||
|
put ' /* vars need extra padding due to JSON escaping of special chars */ ';
|
||||||
|
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) ';
|
||||||
|
put ' ,''l'' ';
|
||||||
|
put ' ); ';
|
||||||
|
put ' run; ';
|
||||||
|
put ' ';
|
||||||
|
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
||||||
|
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
||||||
|
put ' options varlenchk=NOWARN; ';
|
||||||
put ' data _data_(compress=char); ';
|
put ' data _data_(compress=char); ';
|
||||||
|
put ' /* shorten the new vars */ ';
|
||||||
|
put ' length ';
|
||||||
|
put ' %do i=1 %to &numcols; ';
|
||||||
|
put ' &&name&i $&&fmtlen&i ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' ; ';
|
||||||
put ' /* rename on entry */ ';
|
put ' /* rename on entry */ ';
|
||||||
put ' set &ds(rename=( ';
|
put ' set &ds(rename=( ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i=&&newname&i ';
|
put ' &&name&i=&&newname&i ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' )); ';
|
put ' )); ';
|
||||||
put ' &stmt_obs; ';
|
put ' &stmt_obs; ';
|
||||||
put ' /* formatted values can be up to length 32767 */ ';
|
put ' ';
|
||||||
put ' length ';
|
put ' drop ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' &&name&i ';
|
put ' &&newname&i ';
|
||||||
put ' %end; ';
|
|
||||||
put ' $32767; ';
|
|
||||||
put ' retain &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' 0; ';
|
|
||||||
put ' drop &tempvar ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' &&newname&i &&maxlenv&i ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ; ';
|
put ' ; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -388,19 +440,14 @@ data _null_;
|
|||||||
put ' %else %do; ';
|
put ' %else %do; ';
|
||||||
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' /* grab max length of each value as we move down the data step */ ';
|
|
||||||
put ' &tempvar=length(&&name&i); ';
|
|
||||||
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
|
|
||||||
put ' %end; ';
|
|
||||||
put ' if _n_=&lastobs then do; ';
|
|
||||||
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
|
|
||||||
put ' %do i=1 %to &numcols; ';
|
|
||||||
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
|
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
|
put ' if _error_ then do; ';
|
||||||
|
put ' call symputx(''syscc'',1012); ';
|
||||||
|
put ' stop; ';
|
||||||
put ' end; ';
|
put ' end; ';
|
||||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' %let fmtds=&syslast; ';
|
put ' %let fmtds=&syslast; ';
|
||||||
|
put ' options varlenchk=&optval; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' proc format; /* credit yabwon for special null removal */ ';
|
put ' proc format; /* credit yabwon for special null removal */ ';
|
||||||
@@ -415,9 +462,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' other = [best.]; ';
|
put ' other = [best.]; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
|
|
||||||
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
|
|
||||||
put ' options varlenchk=NOWARN; ';
|
|
||||||
put ' data &tempds; ';
|
put ' data &tempds; ';
|
||||||
put ' attrib _all_ label=''''; ';
|
put ' attrib _all_ label=''''; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
@@ -456,7 +500,6 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' run; ';
|
put ' run; ';
|
||||||
put ' options varlenchk=&optval; ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' filename _sjs3 temp lrecl=131068 ; ';
|
put ' filename _sjs3 temp lrecl=131068 ; ';
|
||||||
put ' data _null_; ';
|
put ' data _null_; ';
|
||||||
@@ -546,8 +589,8 @@ data _null_;
|
|||||||
put ' %quote(&user) ';
|
put ' %quote(&user) ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put '%mend mf_getuser; ';
|
put '%mend mf_getuser; ';
|
||||||
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL ';
|
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,stream=Y,missing=NULL ';
|
||||||
put ' ,showmeta=N,maxobs=MAX ';
|
put ' ,showmeta=N,maxobs=MAX,workobs=0 ';
|
||||||
put '); ';
|
put '); ';
|
||||||
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
|
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
|
||||||
put ' sasjs_tables SYS_JES_JOB_URI; ';
|
put ' sasjs_tables SYS_JES_JOB_URI; ';
|
||||||
@@ -654,8 +697,8 @@ data _null_;
|
|||||||
put ' ) ';
|
put ' ) ';
|
||||||
put '%end; ';
|
put '%end; ';
|
||||||
put '%else %if &action=CLOSE %then %do; ';
|
put '%else %if &action=CLOSE %then %do; ';
|
||||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
put ' %if %str(&workobs) > 0 %then %do; ';
|
||||||
put ' /* send back first 10 records of each work table for debugging */ ';
|
put ' /* send back first XX records of each work table for debugging */ ';
|
||||||
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
||||||
put ' ods output Members=&tempds; ';
|
put ' ods output Members=&tempds; ';
|
||||||
put ' proc datasets library=WORK memtype=data; ';
|
put ' proc datasets library=WORK memtype=data; ';
|
||||||
@@ -678,7 +721,9 @@ data _null_;
|
|||||||
put ' put " ""&wt"" : {"; ';
|
put ' put " ""&wt"" : {"; ';
|
||||||
put ' put ''"nlobs":'' nlobs; ';
|
put ' put ''"nlobs":'' nlobs; ';
|
||||||
put ' put '',"nvars":'' nvars; ';
|
put ' put '',"nvars":'' nvars; ';
|
||||||
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10) ';
|
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y ';
|
||||||
|
put ' ,maxobs=&workobs ';
|
||||||
|
put ' ) ';
|
||||||
put ' data _null_; file &fref mod;put "}"; ';
|
put ' data _null_; file &fref mod;put "}"; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' data _null_; file &fref mod;put "}";run; ';
|
put ' data _null_; file &fref mod;put "}";run; ';
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
@param [in] _webout= fileref for returning the json
|
@param [in] _webout= fileref for returning the json
|
||||||
@param [out] fref=(_mvwtemp) Temp fileref to which to write the output
|
@param [out] fref=(_mvwtemp) Temp fileref to which to write the output
|
||||||
@param [out] dslabel= value to use instead of table name for sending to JSON
|
@param [out] dslabel= value to use instead of table name for sending to JSON
|
||||||
@param [in] fmt=(Y) change to N to strip formats from output
|
@param [in] fmt= (N) Setting Y converts all vars to their formatted values
|
||||||
@param [in] stream=(Y) Change to N if not streaming to _webout
|
@param [in] stream=(Y) Change to N if not streaming to _webout
|
||||||
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
|
||||||
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
|
||||||
@@ -35,17 +35,24 @@
|
|||||||
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
|
||||||
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
|
||||||
that should be converted to output JSON
|
that should be converted to output JSON
|
||||||
|
@param [in] workobs= (0) When set to a positive integer, will create a new
|
||||||
|
output object (WORK) which contains this number of observations from all
|
||||||
|
tables in the WORK library.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mp_jsonout.sas
|
@li mp_jsonout.sas
|
||||||
@li mf_getuser.sas
|
@li mf_getuser.sas
|
||||||
|
|
||||||
|
<h4> Related Macros </h4>
|
||||||
|
@li ms_webout.sas
|
||||||
|
@li mm_webout.sas
|
||||||
|
|
||||||
@version Viya 3.3
|
@version Viya 3.3
|
||||||
@author Allan Bowe, source: https://github.com/sasjs/core
|
@author Allan Bowe, source: https://github.com/sasjs/core
|
||||||
|
|
||||||
**/
|
**/
|
||||||
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL
|
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,stream=Y,missing=NULL
|
||||||
,showmeta=N,maxobs=MAX
|
,showmeta=N,maxobs=MAX,workobs=0
|
||||||
);
|
);
|
||||||
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
|
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
|
||||||
sasjs_tables SYS_JES_JOB_URI;
|
sasjs_tables SYS_JES_JOB_URI;
|
||||||
@@ -152,8 +159,8 @@
|
|||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%else %if &action=CLOSE %then %do;
|
%else %if &action=CLOSE %then %do;
|
||||||
%if %str(&_debug) ge 131 %then %do;
|
%if %str(&workobs) > 0 %then %do;
|
||||||
/* send back first 10 records of each work table for debugging */
|
/* send back first XX records of each work table for debugging */
|
||||||
data;run;%let tempds=%scan(&syslast,2,.);
|
data;run;%let tempds=%scan(&syslast,2,.);
|
||||||
ods output Members=&tempds;
|
ods output Members=&tempds;
|
||||||
proc datasets library=WORK memtype=data;
|
proc datasets library=WORK memtype=data;
|
||||||
@@ -176,7 +183,9 @@
|
|||||||
put " ""&wt"" : {";
|
put " ""&wt"" : {";
|
||||||
put '"nlobs":' nlobs;
|
put '"nlobs":' nlobs;
|
||||||
put ',"nvars":' nvars;
|
put ',"nvars":' nvars;
|
||||||
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10)
|
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
|
||||||
|
,maxobs=&workobs
|
||||||
|
)
|
||||||
data _null_; file &fref mod;put "}";
|
data _null_; file &fref mod;put "}";
|
||||||
%end;
|
%end;
|
||||||
data _null_; file &fref mod;put "}";run;
|
data _null_; file &fref mod;put "}";run;
|
||||||
|
|||||||
Reference in New Issue
Block a user