1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-03 23:50:06 +00:00

Compare commits

...

28 Commits

Author SHA1 Message Date
Allan Bowe
984ea44f5d Merge pull request #311 from sasjs/allanbowe/mv-createfile-needs-a-310
feat: adding ctype option to mv_createfile.sas macro
2022-09-13 20:37:28 +01:00
Allan Bowe
88f1222abd Merge branch 'main' into allanbowe/mv-createfile-needs-a-310 2022-09-13 20:37:03 +01:00
Allan Bowe
d88f028ee3 chore: removing ovpn from pipeline 2022-09-06 22:27:40 +00:00
Allan Bowe
07d7c9df4b feat: adding ctype option to mv_createfile.sas macro 2022-09-06 21:20:00 +00:00
munja
6765a1d025 chore(docs): image link 2022-09-03 18:00:00 +01:00
Allan Bowe
952f28a872 Merge pull request #309 from sasjs/dictionary
feat: new mp_dictionary() table
2022-09-03 16:53:05 +01:00
munja
8246b5a42c feat: new mp_dictionary() table 2022-09-03 16:50:11 +01:00
Allan Bowe
72123aeeb7 Merge pull request #305 from sasjs/cli1229
Making _addjesbeginendmacros configurable
2022-08-25 14:21:04 +01:00
Allan Bowe
236d1ae25f Merge branch 'main' into cli1229 2022-08-25 14:20:57 +01:00
munja
b75369b28d fix: pgm uninitialised in mm_getstpinfo 2022-08-23 16:00:42 +01:00
Allan Bowe
63871db170 Merge pull request #308 from sasjs/allanbowe/mp-jsonout-does-not-replace-307
fix: support for SUB (1A) hex char in DATASTEP generated JSON.
2022-08-22 14:16:13 +01:00
Allan Bowe
6456c2f6e2 fix: support for SUB (1A) hex char in DATASTEP generated JSON. Closes #307 2022-08-22 13:14:20 +00:00
munja
36faa194a8 chore(docs): more related files in mp_dsmeta.sas 2022-08-21 21:15:24 +01:00
munja
093dc87aad chore(docs): crediting louise 2022-08-21 19:55:02 +01:00
munja
ca045e3ebf chore(docs): typo 2022-08-21 19:27:52 +01:00
Allan Bowe
be5e2f371d Merge pull request #306 from sasjs/mp_dsmeta
feat: new mp_dsmeta macro
2022-08-21 19:18:56 +01:00
munja
6d15465bac fix: generating all.sas and fixing failing test 2022-08-21 19:17:56 +01:00
munja
2031a5b0c0 feat: new mp_dsmeta macro 2022-08-21 19:01:01 +01:00
Allan Bowe
7b3844a391 chore: updating all.sas 2022-08-21 16:02:20 +00:00
Allan Bowe
202de36042 fix: options to remove _addjesbeginendmacros from Viya Jobs 2022-08-21 16:01:50 +00:00
Allan Bowe
62837b512b feat: mm_getstpinfo.sas
Actually this came from a previous commit but the message was squashed out:  1b5effd584
2022-08-19 11:28:15 +01:00
Allan Bowe
5d5a99fd77 Merge pull request #304 from sasjs/allanbowe/need-a-macro-to-extract-303
chore(lint): reduce length
2022-08-19 11:00:00 +01:00
Allan Bowe
1b5effd584 chore(lint): reduce length 2022-08-19 09:58:42 +00:00
Allan Bowe
1613ab2c9e Merge pull request #302 from sasjs/allanbowe/proc-format-max-can-be-300
fix: switching MAX for LENGTH to get max label value.  Closes #300
2022-08-17 21:59:14 +01:00
Allan Bowe
a2df4e35be fix: switching MAX for LENGTH to get max label value. Closes #300 2022-08-17 20:54:14 +00:00
Allan Bowe
aabbcfdf6b Merge pull request #299 from sasjs/allanbowe/remove-work-tables-from-298
fix: removing automatic dump of WORK tables in mX_webout macros.  Clo…
2022-08-15 18:48:06 +01:00
Allan Bowe
7b7759e1ce chore: fix renegade closing bracket 2022-08-15 17:44:24 +00:00
Allan Bowe
e5a3053600 fix: removing automatic dump of WORK tables in mX_webout macros. Closes 298 2022-08-15 17:21:00 +00:00
20 changed files with 803 additions and 235 deletions

View File

@@ -1,30 +0,0 @@
cipher AES-256-CBC
setenv FORWARD_COMPATIBLE 1
client
server-poll-timeout 4
nobind
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 443 tcp
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 1194 udp
remote vpn.analytium.co.uk 1194 udp
dev tun
dev-type tun
ns-cert-type server
setenv opt tls-version-min 1.0 or-highest
reneg-sec 604800
sndbuf 0
rcvbuf 0
# NOTE: LZO commands are pushed by the Access Server at connect time.
# NOTE: The below line doesn't disable LZO.
comp-lzo no
verb 3
setenv PUSH_PEER_INFO
ca ca.crt
cert user.crt
key user.key
tls-auth tls.key 1

View File

@@ -21,31 +21,6 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Write VPN Files
run: |
echo "$CA_CRT" > .github/vpn/ca.crt
echo "$USER_CRT" > .github/vpn/user.crt
echo "$USER_KEY" > .github/vpn/user.key
echo "$TLS_KEY" > .github/vpn/tls.key
shell: bash
env:
CA_CRT: ${{ secrets.CA_CRT}}
USER_CRT: ${{ secrets.USER_CRT }}
USER_KEY: ${{ secrets.USER_KEY }}
TLS_KEY: ${{ secrets.TLS_KEY }}
- name: Install Open VPN
run: |
sudo apt install apt-transport-https
sudo wget https://swupdate.openvpn.net/repos/openvpn-repo-pkg-key.pub
sudo apt-key add openvpn-repo-pkg-key.pub
sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-focal.list
sudo apt update
sudo apt install openvpn3
- name: Start Open VPN 3
run: openvpn3 session-start --config .github/vpn/config.ovpn
- name: Install Doxygen - name: Install Doxygen
run: sudo apt-get install doxygen run: sudo apt-get install doxygen
@@ -78,7 +53,5 @@ jobs:
SECRET: ${{secrets.SECRET}} SECRET: ${{secrets.SECRET}}
SAS_USERNAME: ${{secrets.SAS_USERNAME}} SAS_USERNAME: ${{secrets.SAS_USERNAME}}
SAS_PASSWORD: ${{secrets.SAS_PASSWORD}} SAS_PASSWORD: ${{secrets.SAS_PASSWORD}}
SERVER_URL: ${{secrets.SERVER_URL}}
SERVER_TYPE: ${{secrets.SERVER_TYPE}}
ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}} ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}}
REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}} REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}}

View File

@@ -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

452
all.sas
View File

@@ -4112,11 +4112,14 @@ proc sql;
%mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES) %mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES)
%mp_createconstraints(inds=work.constraints,outds=created,execute=YES) %mp_createconstraints(inds=work.constraints,outds=created,execute=YES)
@param inds= The input table containing the constraint info @param inds= (work.mp_getconstraints) The input table containing the
@param outds= a table containing the create statements (create_statement column) constraint info
@param execute= `YES|NO` - default is NO. To actually create, use YES. @param outds= (work.mp_createconstraints) A table containing the create
statements (create_statement column)
@param execute= (NO) To actually create, use YES.
<h4> SAS Macros </h4> <h4> Related Files </h4>
@li mp_getconstraints.sas
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@@ -4124,7 +4127,7 @@ proc sql;
**/ **/
%macro mp_createconstraints(inds=mp_getconstraints %macro mp_createconstraints(inds=mp_getconstraints
,outds=mp_createconstraints ,outds=work.mp_createconstraints
,execute=NO ,execute=NO
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -4158,7 +4161,8 @@ data &outds;
output; output;
run; run;
%mend mp_createconstraints;/** %mend mp_createconstraints;
/**
@file mp_createwebservice.sas @file mp_createwebservice.sas
@brief Create a web service in SAS 9, Viya or SASjs Server @brief Create a web service in SAS 9, Viya or SASjs Server
@details This is actually a wrapper for mx_createwebservice.sas, remaining @details This is actually a wrapper for mx_createwebservice.sas, remaining
@@ -4450,6 +4454,58 @@ run;
%end; %end;
%else %put &sysmacroname: &folder: is not a valid / accessible folder. ; %else %put &sysmacroname: &folder: is not a valid / accessible folder. ;
%mend mp_deletefolder;/** %mend mp_deletefolder;/**
@file mp_dictionary.sas
@brief Creates a portal (libref) into the SQL Dictionary Views
@details Provide a libref and the macro will create a series of views against
each view in the special PROC SQL dictionary libref.
This is useful if you would like to visualise (navigate) the views in a SAS
client such as Base SAS, Enterprise Guide, or Studio (or [Data Controller](
https://datacontroller.io)).
It works by extracting the dictionary.dictionaries view into
YOURLIB.dictionaries, then uses that to create a YOURLIB.{viewName} for every
other dictionary.view, eg:
proc sql;
create view YOURLIB.columns as select * from dictionary.columns;
Usage:
libname demo "/lib/directory";
%mp_dictionary(lib=demo)
Or, to just create them in WORK:
%mp_dictionary()
If you'd just like to browse the dictionary data model, you can also check
out [this article](https://rawsas.com/dictionary-of-dictionaries/).
![](https://user-images.githubusercontent.com/4420615/188278365-2987db97-0594-4a39-ac81-dbacdef5cdc8.png)
@param lib= (WORK) The libref in which to create the views
<h4> Related Files </h4>
@li mp_dictionary.test.sas
@version 9.2
@author Allan Bowe
**/
%macro mp_dictionary(lib=WORK)/*/STORE SOURCE*/;
%local list i mem;
proc sql noprint;
create view &lib..dictionaries as select * from dictionary.dictionaries;
select distinct memname into: list separated by ' ' from &lib..dictionaries;
%do i=1 %to %sysfunc(countw(&list,%str( )));
%let mem=%scan(&list,&i,%str( ));
create view &lib..&mem as select * from dictionary.&mem;
%end;
quit;
%mend mp_dictionary;
/**
@file @file
@brief Returns all files and subdirectories within a specified parent @brief Returns all files and subdirectories within a specified parent
@details When used with getattrs=NO, is not OS specific (uses dopen / dread). @details When used with getattrs=NO, is not OS specific (uses dopen / dread).
@@ -5826,6 +5882,116 @@ options varlenchk=&optval;
%put &sysmacroname: &outds is %mf_getfilesize(libds=&outds,format=yes); %put &sysmacroname: &outds is %mf_getfilesize(libds=&outds,format=yes);
%mend mp_ds2squeeze;/** %mend mp_ds2squeeze;/**
@file
@brief Export dataset metadata to a single output table
@details Exports the dataset attributes and enginehost information, then
converts the datasets into a single output table in the following format:
|ODS_TABLE:$10.|NAME:$100.|VALUE:$1000.|
|---|---|---|
|`ATTRIBUTES `|`Data Set Name `|`SASHELP.CLASS `|
|`ATTRIBUTES `|`Observations `|`19 `|
|`ATTRIBUTES `|`Member Type `|`DATA `|
|`ATTRIBUTES `|`Variables `|`5 `|
|`ATTRIBUTES `|`Engine `|`V9 `|
|`ATTRIBUTES `|`Indexes `|`0 `|
|`ATTRIBUTES `|`Created `|`06/08/2020 00:59:14 `|
|`ATTRIBUTES `|`Observation Length `|`40 `|
|`ATTRIBUTES `|`Last Modified `|`06/08/2020 00:59:14 `|
|`ATTRIBUTES `|`Deleted Observations `|`0 `|
|`ATTRIBUTES `|`Protection `|`. `|
|`ATTRIBUTES `|`Compressed `|`NO `|
|`ATTRIBUTES `|`Data Set Type `|`. `|
|`ATTRIBUTES `|`Sorted `|`NO `|
|`ATTRIBUTES `|`Label `|`Student Data `|
|`ATTRIBUTES `|`Data Representation `|`SOLARIS_X86_64, LINUX_X86_64, ALPHA_TRU64, LINUX_IA64 `|
|`ATTRIBUTES `|`Encoding `|`us-ascii ASCII (ANSI) `|
|`ENGINEHOST `|`Data Set Page Size `|`65536 `|
|`ENGINEHOST `|`Number of Data Set Pages `|`1 `|
|`ENGINEHOST `|`First Data Page `|`1 `|
|`ENGINEHOST `|`Max Obs per Page `|`1632 `|
|`ENGINEHOST `|`Obs in First Data Page `|`19 `|
|`ENGINEHOST `|`Number of Data Set Repairs `|`0 `|
|`ENGINEHOST `|`Filename `|`/opt/sas/sas9/SASHome/SASFoundation/9.4/sashelp/class.sas7bdat `|
|`ENGINEHOST `|`Release Created `|`9.0401M7 `|
|`ENGINEHOST `|`Host Created `|`Linux `|
|`ENGINEHOST `|`Inode Number `|`28314616 `|
|`ENGINEHOST `|`Access Permission `|`rw-r--r-- `|
|`ENGINEHOST `|`Owner Name `|`sas `|
|`ENGINEHOST `|`File Size `|`128KB `|
|`ENGINEHOST `|`File Size (bytes) `|`131072 `|
Example usage:
%mp_dsmeta(sashelp.class,outds=work.mymeta)
proc print data=work.mymeta;
run;
For more details on creating datasets from PROC CONTENTS check out this
excellent [paper](
https://support.sas.com/resources/papers/proceedings14/1549-2014.pdf) by
[Louise Hadden](https://www.linkedin.com/in/louisehadden/).
@param libds The library.dataset to export the metadata for
@param outds= (work.dsmeta) The output table to contain the metadata
<h4> Related Files </h4>
@li mp_dsmeta.test.sas
@li mp_getcols.sas
@li mp_getdbml.sas
@li mp_getddl.sas
@li mp_getformats.sas
@li mp_getpk.sas
@li mp_guesspk.sas
**/
%macro mp_dsmeta(libds,outds=work.dsmeta);
%local ds1 ds2;
data;run; %let ds1=&syslast;
data;run; %let ds2=&syslast;
/* setup the ODS capture */
ods output attributes=&ds1 enginehost=&ds2;
/* export the metadata */
proc contents data=&libds;
run;
/* load it into a single table */
data &outds (keep=ods_table name value);
length ods_table $10 name label2 label1 label $100
value cvalue cvalue1 cvalue2 $1000
nvalue nvalue1 nvalue2 8;
if _n_=1 then call missing (of _all_);
* putlog (_all_)(=);
set &ds1 (in=atrs) &ds2 (in=eng);
if atrs then do;
ods_table='ATTRIBUTES';
name=coalescec(label1,label);
value=coalescec(cvalue1,cvalue,put(coalesce(nvalue1,nvalue),best.));
output;
if label2 ne '' then do;
name=label2;
value=coalescec(cvalue2,put(nvalue2,best.));
output;
end;
end;
else if eng then do;
ods_table='ENGINEHOST';
name=coalescec(label1,label);
value=coalescec(cvalue1,cvalue,put(coalesce(nvalue1,nvalue),best.));
output;
end;
run;
proc sql;
drop table &ds1, &ds2;
%mend mp_dsmeta;
/**
@file @file
@brief Checks an input filter table for validity @brief Checks an input filter table for validity
@details Performs checks on the input table to ensure it arrives in the @details Performs checks on the input table to ensure it arrives in the
@@ -8709,7 +8875,7 @@ options
@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
@@ -8793,7 +8959,7 @@ options
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 */ /* overwritten when fmt=Y and a custom format exists in catalog */
if typelong='num' then call symputx(cats('fmtlen',_n_),200,'l'); 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'); else call symputx(cats('fmtlen',_n_),min(32767,ceil((length+10)*1.5)),'l');
run; run;
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
@@ -8849,15 +9015,15 @@ options
%let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
proc sql noprint; proc sql noprint;
create table &tmpds1 as create table &tmpds1 as
select cats(libname,'.',memname) as fmtcat, select cats(libname,'.',memname) as FMTCAT,
fmtname FMTNAME
from dictionary.formats from dictionary.formats
where fmttype='F' and libname is not null where fmttype='F' and libname is not null
and fmtname in (select format from &colinfo where format is not null) and fmtname in (select format from &colinfo where format is not null)
order by 1; order by 1;
create table &tmpds2( create table &tmpds2(
FMTNAME char(32), FMTNAME char(32),
MAX num length=3 LENGTH num
); );
%local catlist cat fmtlist i; %local catlist cat fmtlist i;
select distinct fmtcat into: catlist separated by ' ' from &tmpds1; select distinct fmtcat into: catlist separated by ' ' from &tmpds1;
@@ -8866,16 +9032,16 @@ options
proc sql; proc sql;
select distinct fmtname into: fmtlist separated by ' ' select distinct fmtname into: fmtlist separated by ' '
from &tmpds1 where fmtcat="&cat"; from &tmpds1 where fmtcat="&cat";
proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); proc format lib=&cat cntlout=&tmpds3(keep=fmtname length);
select &fmtlist; select &fmtlist;
run; run;
proc sql; proc sql;
insert into &tmpds2 select distinct fmtname,max from &tmpds3; insert into &tmpds2 select distinct fmtname,length from &tmpds3;
%end; %end;
proc sql; proc sql;
create table &tmpds4 as create table &tmpds4 as
select a.*, b.max as maxw select a.*, b.length as MAXW
from &colinfo a from &colinfo a
left join &tmpds2 b left join &tmpds2 b
on cats(a.format)=cats(upcase(b.fmtname)) on cats(a.format)=cats(upcase(b.fmtname))
@@ -8886,7 +9052,7 @@ options
call symputx( call symputx(
cats('fmtlen',_n_), cats('fmtlen',_n_),
/* vars need extra padding due to JSON escaping of special chars */ /* vars need extra padding due to JSON escaping of special chars */
min(32767,ceil((max(length,maxw)+3)*1.5)) min(32767,ceil((max(length,maxw)+10)*1.5))
,'l' ,'l'
); );
run; run;
@@ -8961,7 +9127,7 @@ options
format _numeric_ bart.; format _numeric_ bart.;
%do i=1 %to &numcols; %do i=1 %to &numcols;
%if &&typelong&i=char or &fmt=Y %then %do; %if &&typelong&i=char or &fmt=Y %then %do;
if findc(&&name&i,'"\'!!'0A0D09000E0F01021011'x) then do; if findc(&&name&i,'"\'!!'0A0D09000E0F010210111A'x) then do;
&&name&i='"'!!trim( &&name&i='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */ prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */ prxchange('s/\x0A/\n/',-1, /* new line */
@@ -8974,8 +9140,9 @@ options
prxchange('s/\x02/\\u0002/',-1, /* STX */ prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */ prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */ prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
))))))))))))!!'"'; )))))))))))))!!'"';
end; end;
else &&name&i=quote(cats(&&name&i)); else &&name&i=quote(cats(&&name&i));
%end; %end;
@@ -15288,7 +15455,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -15344,15 +15511,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -15361,16 +15528,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -15381,7 +15548,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -15456,7 +15623,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -15469,8 +15636,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -15566,7 +15734,7 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,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; ';
@@ -15639,8 +15807,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; ';
@@ -15664,7 +15832,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; ';
@@ -17657,6 +17827,73 @@ filename __getdoc clear;
%end; %end;
%mend mm_getstpcode; %mend mm_getstpcode;
/**
@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 " path;
put (_all_)(=);
end;
&md.put (_all_)(=);
run;
%mend mm_getstpinfo ;
/** /**
@file @file
@brief Returns a dataset with all Stored Processes, or just those in a @brief Returns a dataset with all Stored Processes, or just those in a
@@ -19125,6 +19362,9 @@ run;
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
@@ -19140,7 +19380,7 @@ run;
**/ **/
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,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;
@@ -19213,8 +19453,8 @@ run;
%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;
@@ -19238,7 +19478,9 @@ run;
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;
@@ -20235,7 +20477,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -20291,15 +20533,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -20308,16 +20550,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -20328,7 +20570,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -20403,7 +20645,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -20416,8 +20658,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -20514,7 +20757,7 @@ data _null_;
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put ' '; put ' ';
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,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; ';
@@ -20577,8 +20820,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; ';
@@ -20603,7 +20846,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; ';
@@ -21488,6 +21733,9 @@ run;
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
@@ -21506,7 +21754,7 @@ run;
**/ **/
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,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;
@@ -21569,8 +21817,8 @@ run;
) )
%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;
@@ -21595,7 +21843,9 @@ run;
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;
@@ -21765,7 +22015,8 @@ run;
@param [in] contentdisp= (inline) Content Disposition. Example values: @param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline @li inline
@li attachment @li attachment
@param [in] ctype= (0) Set a default HTTP Content-Type header to be returned
with the file when the content is retrieved from the Files service.
@param [in] access_token_var= The global macro variable to contain the access @param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type. token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are: @param [in] grant_type= (sas_services) Valid values are:
@@ -21793,6 +22044,7 @@ run;
,inref= ,inref=
,intype=BINARY ,intype=BINARY
,contentdisp=inline ,contentdisp=inline
,ctype=0
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
@@ -21844,8 +22096,10 @@ filename &fref filesrvc
folderPath="&path" folderPath="&path"
filename="&name" filename="&name"
cdisp="&contentdisp" cdisp="&contentdisp"
%if "&ctype" ne "0" %then %do;
ctype="&ctype"
%end;
lrecl=1048544; lrecl=1048544;
%if &intype=BINARY %then %do; %if &intype=BINARY %then %do;
%mp_binarycopy(inref=&inref, outref=&fref) %mp_binarycopy(inref=&inref, outref=&fref)
%end; %end;
@@ -22082,14 +22336,25 @@ options noquotelenmax;
@param path= The full path (on SAS Drive) where the job will be created @param path= The full path (on SAS Drive) where the job will be created
@param name= The name of the job @param name= The name of the job
@param desc= The description of the job @param desc= (Created by the mv_createjob.sas macro) The job description
@param precode= Space separated list of filerefs, pointing to the code that @param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the job needs to be attached to the beginning of the job
@param code= Fileref(s) of the actual code to be added @param code= (ft15f001) Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token @param access_token_var= (ACCESS_TOKEN) Global macro variable containing the
@param grant_type= valid values are "password" or "authorization_code" access token
(unquoted). The default is authorization_code. @param grant_type= (sas_services) Valid values:
@param replace= select NO to avoid replacing any existing job in that location @li sas_services
@li detect
@li authorization_code
@li password
@param replace= (YES) select NO to avoid replacing any existing job
@param addjesbeginendmacros= (false) Relates to the `_addjesbeginendmacros`
setting. Normally this would always be false however due to a Viya bug
(https://github.com/sasjs/cli/issues/1229) this is now configurable. Valid
values:
@li true
@li false
@li 0 - this will prevent the flag from being set (job will default to true)
@param contextname= Choose a specific context on which to run the Job. Leave @param contextname= Choose a specific context on which to run the Job. Leave
blank to use the default context. From Viya 3.5 it is possible to configure blank to use the default context. From Viya 3.5 it is possible to configure
a shared context - see a shared context - see
@@ -22110,6 +22375,7 @@ https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5p
,replace=YES ,replace=YES
,debug=0 ,debug=0
,contextname= ,contextname=
,addjesbeginendmacros=false
); );
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -22233,19 +22499,29 @@ run;
%end; %end;
/* set up the body of the request to create the service */ /* set up the body of the request to create the service */
%local fname3; %local fname3 comma;
%let fname3=%mf_getuniquefileref(); %let fname3=%mf_getuniquefileref();
data _null_; data _null_;
file &fname3 TERMSTR=' '; file &fname3 TERMSTR=' ';
length string $32767; length string $32767;
string=cats('{"version": 0,"name":"' string=cats('{"version": 0,"name":"'
,"&name" ,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"' ,'","type":"Compute","parameters":['
,',"type":"CHARACTER","defaultValue":"false"}'); %if &addjesbeginendmacros ne 0 %then %do;
,'{"name":"_addjesbeginendmacros"'
,',"type":"CHARACTER","defaultValue":"'
,"&addjesbeginendmacros"
,'"}'
%let comma=%str(,);
%end;
);
context=quote(cats(symget('contextname'))); context=quote(cats(symget('contextname')));
if context ne '""' then do; if context ne '""' then do;
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":' string=cats(string
,context,',"type":"CHARACTER","label":"Context Name","required": false}'); ,"&comma"
,'{"version": 1,"name": "_contextName","defaultValue":'
,context,',"type":"CHARACTER","label":"Context Name","required": false}'
);
end; end;
string=cats(string,'],"code":"'); string=cats(string,'],"code":"');
put string; put string;
@@ -22691,7 +22967,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -22747,15 +23023,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -22764,16 +23040,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -22784,7 +23060,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -22859,7 +23135,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -22872,8 +23148,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -22969,7 +23246,7 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,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; ';
@@ -23076,8 +23353,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; ';
@@ -23100,7 +23377,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; ';
@@ -26757,6 +27036,9 @@ filename &fref1 clear;
`,"$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
@@ -26771,7 +27053,7 @@ filename &fref1 clear;
**/ **/
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,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;
@@ -26878,8 +27160,8 @@ filename &fref1 clear;
) )
%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;
@@ -26902,7 +27184,9 @@ filename &fref1 clear;
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;

View File

@@ -18,11 +18,14 @@
%mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES) %mp_deleteconstraints(inds=work.constraints,outds=dropped,execute=YES)
%mp_createconstraints(inds=work.constraints,outds=created,execute=YES) %mp_createconstraints(inds=work.constraints,outds=created,execute=YES)
@param inds= The input table containing the constraint info @param inds= (work.mp_getconstraints) The input table containing the
@param outds= a table containing the create statements (create_statement column) constraint info
@param execute= `YES|NO` - default is NO. To actually create, use YES. @param outds= (work.mp_createconstraints) A table containing the create
statements (create_statement column)
@param execute= (NO) To actually create, use YES.
<h4> SAS Macros </h4> <h4> Related Files </h4>
@li mp_getconstraints.sas
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
@@ -30,7 +33,7 @@
**/ **/
%macro mp_createconstraints(inds=mp_getconstraints %macro mp_createconstraints(inds=mp_getconstraints
,outds=mp_createconstraints ,outds=work.mp_createconstraints
,execute=NO ,execute=NO
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -64,4 +67,4 @@ data &outds;
output; output;
run; run;
%mend mp_createconstraints; %mend mp_createconstraints;

52
base/mp_dictionary.sas Normal file
View File

@@ -0,0 +1,52 @@
/**
@file mp_dictionary.sas
@brief Creates a portal (libref) into the SQL Dictionary Views
@details Provide a libref and the macro will create a series of views against
each view in the special PROC SQL dictionary libref.
This is useful if you would like to visualise (navigate) the views in a SAS
client such as Base SAS, Enterprise Guide, or Studio (or [Data Controller](
https://datacontroller.io)).
It works by extracting the dictionary.dictionaries view into
YOURLIB.dictionaries, then uses that to create a YOURLIB.{viewName} for every
other dictionary.view, eg:
proc sql;
create view YOURLIB.columns as select * from dictionary.columns;
Usage:
libname demo "/lib/directory";
%mp_dictionary(lib=demo)
Or, to just create them in WORK:
%mp_dictionary()
If you'd just like to browse the dictionary data model, you can also check
out [this article](https://rawsas.com/dictionary-of-dictionaries/).
![](https://user-images.githubusercontent.com/4420615/188278365-2987db97-0594-4a39-ac81-dbacdef5cdc8.png)
@param lib= (WORK) The libref in which to create the views
<h4> Related Files </h4>
@li mp_dictionary.test.sas
@version 9.2
@author Allan Bowe
**/
%macro mp_dictionary(lib=WORK)/*/STORE SOURCE*/;
%local list i mem;
proc sql noprint;
create view &lib..dictionaries as select * from dictionary.dictionaries;
select distinct memname into: list separated by ' ' from &lib..dictionaries;
%do i=1 %to %sysfunc(countw(&list,%str( )));
%let mem=%scan(&list,&i,%str( ));
create view &lib..&mem as select * from dictionary.&mem;
%end;
quit;
%mend mp_dictionary;

110
base/mp_dsmeta.sas Normal file
View File

@@ -0,0 +1,110 @@
/**
@file
@brief Export dataset metadata to a single output table
@details Exports the dataset attributes and enginehost information, then
converts the datasets into a single output table in the following format:
|ODS_TABLE:$10.|NAME:$100.|VALUE:$1000.|
|---|---|---|
|`ATTRIBUTES `|`Data Set Name `|`SASHELP.CLASS `|
|`ATTRIBUTES `|`Observations `|`19 `|
|`ATTRIBUTES `|`Member Type `|`DATA `|
|`ATTRIBUTES `|`Variables `|`5 `|
|`ATTRIBUTES `|`Engine `|`V9 `|
|`ATTRIBUTES `|`Indexes `|`0 `|
|`ATTRIBUTES `|`Created `|`06/08/2020 00:59:14 `|
|`ATTRIBUTES `|`Observation Length `|`40 `|
|`ATTRIBUTES `|`Last Modified `|`06/08/2020 00:59:14 `|
|`ATTRIBUTES `|`Deleted Observations `|`0 `|
|`ATTRIBUTES `|`Protection `|`. `|
|`ATTRIBUTES `|`Compressed `|`NO `|
|`ATTRIBUTES `|`Data Set Type `|`. `|
|`ATTRIBUTES `|`Sorted `|`NO `|
|`ATTRIBUTES `|`Label `|`Student Data `|
|`ATTRIBUTES `|`Data Representation `|`SOLARIS_X86_64, LINUX_X86_64, ALPHA_TRU64, LINUX_IA64 `|
|`ATTRIBUTES `|`Encoding `|`us-ascii ASCII (ANSI) `|
|`ENGINEHOST `|`Data Set Page Size `|`65536 `|
|`ENGINEHOST `|`Number of Data Set Pages `|`1 `|
|`ENGINEHOST `|`First Data Page `|`1 `|
|`ENGINEHOST `|`Max Obs per Page `|`1632 `|
|`ENGINEHOST `|`Obs in First Data Page `|`19 `|
|`ENGINEHOST `|`Number of Data Set Repairs `|`0 `|
|`ENGINEHOST `|`Filename `|`/opt/sas/sas9/SASHome/SASFoundation/9.4/sashelp/class.sas7bdat `|
|`ENGINEHOST `|`Release Created `|`9.0401M7 `|
|`ENGINEHOST `|`Host Created `|`Linux `|
|`ENGINEHOST `|`Inode Number `|`28314616 `|
|`ENGINEHOST `|`Access Permission `|`rw-r--r-- `|
|`ENGINEHOST `|`Owner Name `|`sas `|
|`ENGINEHOST `|`File Size `|`128KB `|
|`ENGINEHOST `|`File Size (bytes) `|`131072 `|
Example usage:
%mp_dsmeta(sashelp.class,outds=work.mymeta)
proc print data=work.mymeta;
run;
For more details on creating datasets from PROC CONTENTS check out this
excellent [paper](
https://support.sas.com/resources/papers/proceedings14/1549-2014.pdf) by
[Louise Hadden](https://www.linkedin.com/in/louisehadden/).
@param libds The library.dataset to export the metadata for
@param outds= (work.dsmeta) The output table to contain the metadata
<h4> Related Files </h4>
@li mp_dsmeta.test.sas
@li mp_getcols.sas
@li mp_getdbml.sas
@li mp_getddl.sas
@li mp_getformats.sas
@li mp_getpk.sas
@li mp_guesspk.sas
**/
%macro mp_dsmeta(libds,outds=work.dsmeta);
%local ds1 ds2;
data;run; %let ds1=&syslast;
data;run; %let ds2=&syslast;
/* setup the ODS capture */
ods output attributes=&ds1 enginehost=&ds2;
/* export the metadata */
proc contents data=&libds;
run;
/* load it into a single table */
data &outds (keep=ods_table name value);
length ods_table $10 name label2 label1 label $100
value cvalue cvalue1 cvalue2 $1000
nvalue nvalue1 nvalue2 8;
if _n_=1 then call missing (of _all_);
* putlog (_all_)(=);
set &ds1 (in=atrs) &ds2 (in=eng);
if atrs then do;
ods_table='ATTRIBUTES';
name=coalescec(label1,label);
value=coalescec(cvalue1,cvalue,put(coalesce(nvalue1,nvalue),best.));
output;
if label2 ne '' then do;
name=label2;
value=coalescec(cvalue2,put(nvalue2,best.));
output;
end;
end;
else if eng then do;
ods_table='ENGINEHOST';
name=coalescec(label1,label);
value=coalescec(cvalue1,cvalue,put(coalesce(nvalue1,nvalue),best.));
output;
end;
run;
proc sql;
drop table &ds1, &ds2;
%mend mp_dsmeta;

View File

@@ -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
@@ -146,7 +146,7 @@
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 */ /* overwritten when fmt=Y and a custom format exists in catalog */
if typelong='num' then call symputx(cats('fmtlen',_n_),200,'l'); 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'); else call symputx(cats('fmtlen',_n_),min(32767,ceil((length+10)*1.5)),'l');
run; run;
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
@@ -202,15 +202,15 @@
%let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
proc sql noprint; proc sql noprint;
create table &tmpds1 as create table &tmpds1 as
select cats(libname,'.',memname) as fmtcat, select cats(libname,'.',memname) as FMTCAT,
fmtname FMTNAME
from dictionary.formats from dictionary.formats
where fmttype='F' and libname is not null where fmttype='F' and libname is not null
and fmtname in (select format from &colinfo where format is not null) and fmtname in (select format from &colinfo where format is not null)
order by 1; order by 1;
create table &tmpds2( create table &tmpds2(
FMTNAME char(32), FMTNAME char(32),
MAX num length=3 LENGTH num
); );
%local catlist cat fmtlist i; %local catlist cat fmtlist i;
select distinct fmtcat into: catlist separated by ' ' from &tmpds1; select distinct fmtcat into: catlist separated by ' ' from &tmpds1;
@@ -219,16 +219,16 @@
proc sql; proc sql;
select distinct fmtname into: fmtlist separated by ' ' select distinct fmtname into: fmtlist separated by ' '
from &tmpds1 where fmtcat="&cat"; from &tmpds1 where fmtcat="&cat";
proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); proc format lib=&cat cntlout=&tmpds3(keep=fmtname length);
select &fmtlist; select &fmtlist;
run; run;
proc sql; proc sql;
insert into &tmpds2 select distinct fmtname,max from &tmpds3; insert into &tmpds2 select distinct fmtname,length from &tmpds3;
%end; %end;
proc sql; proc sql;
create table &tmpds4 as create table &tmpds4 as
select a.*, b.max as maxw select a.*, b.length as MAXW
from &colinfo a from &colinfo a
left join &tmpds2 b left join &tmpds2 b
on cats(a.format)=cats(upcase(b.fmtname)) on cats(a.format)=cats(upcase(b.fmtname))
@@ -239,7 +239,7 @@
call symputx( call symputx(
cats('fmtlen',_n_), cats('fmtlen',_n_),
/* vars need extra padding due to JSON escaping of special chars */ /* vars need extra padding due to JSON escaping of special chars */
min(32767,ceil((max(length,maxw)+3)*1.5)) min(32767,ceil((max(length,maxw)+10)*1.5))
,'l' ,'l'
); );
run; run;
@@ -314,7 +314,7 @@
format _numeric_ bart.; format _numeric_ bart.;
%do i=1 %to &numcols; %do i=1 %to &numcols;
%if &&typelong&i=char or &fmt=Y %then %do; %if &&typelong&i=char or &fmt=Y %then %do;
if findc(&&name&i,'"\'!!'0A0D09000E0F01021011'x) then do; if findc(&&name&i,'"\'!!'0A0D09000E0F010210111A'x) then do;
&&name&i='"'!!trim( &&name&i='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */ prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */ prxchange('s/\x0A/\n/',-1, /* new line */
@@ -327,8 +327,9 @@
prxchange('s/\x02/\\u0002/',-1, /* STX */ prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */ prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */ prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
))))))))))))!!'"'; )))))))))))))!!'"';
end; end;
else &&name&i=quote(cats(&&name&i)); else &&name&i=quote(cats(&&name&i));
%end; %end;

View File

@@ -169,7 +169,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -225,15 +225,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -242,16 +242,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -262,7 +262,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -337,7 +337,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -350,8 +350,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -447,7 +448,7 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,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; ';
@@ -520,8 +521,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; ';
@@ -545,7 +546,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
View 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 " path;
put (_all_)(=);
end;
&md.put (_all_)(=);
run;
%mend mm_getstpinfo ;

View File

@@ -34,6 +34,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
@@ -49,7 +52,7 @@
**/ **/
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=N,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;
@@ -122,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;
@@ -147,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;

View File

@@ -107,4 +107,4 @@
"contextName": "SAS Job Execution compute context" "contextName": "SAS Job Execution compute context"
} }
] ]
} }

View File

@@ -170,7 +170,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -226,15 +226,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -243,16 +243,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -263,7 +263,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -338,7 +338,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -351,8 +351,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -449,7 +450,7 @@ data _null_;
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put ' '; put ' ';
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,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; ';
@@ -512,8 +513,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; ';
@@ -538,7 +539,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; ';

View File

@@ -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
@@ -49,7 +52,7 @@
**/ **/
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=N,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;

View File

@@ -0,0 +1,26 @@
/**
@file
@brief Testing mp_dictionary.sas macro
<h4> SAS Macros </h4>
@li mp_dictionary.sas
@li mp_assert.sas
**/
libname test (work);
%mp_dictionary(lib=test)
proc sql;
create table work.compare1 as select * from test.styles;
create table work.compare2 as select * from dictionary.styles;
proc compare base=compare1 compare=compare2;
run;
%put _all_;
%mp_assert(
iftrue=(%mf_existds(&sysinfo)=0),
desc=Compare was exact,
outds=work.test_results
)

View File

@@ -0,0 +1,32 @@
/**
@file
@brief Testing mp_dsmeta.sas macro
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mp_assertscope.sas
@li mp_dsmeta.sas
**/
data work.Example;
set sashelp.vmacro;
run;
%mp_assertscope(SNAPSHOT)
%mp_dsmeta(work.example,outds=work.test)
%mp_assertscope(COMPARE)
proc sql noprint;
select count(*) into: nobs from work.test;
select count(distinct ods_table) into: tnobs from work.test;
%mp_assert(
iftrue=(&tnobs=2),
desc=Check that both ATTRIBUTES and ENGINEHOST are provided
)
%mp_assert(
iftrue=(&nobs>10),
desc=Check that sufficient details are provided
)

View File

@@ -24,7 +24,8 @@
@param [in] contentdisp= (inline) Content Disposition. Example values: @param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline @li inline
@li attachment @li attachment
@param [in] ctype= (0) Set a default HTTP Content-Type header to be returned
with the file when the content is retrieved from the Files service.
@param [in] access_token_var= The global macro variable to contain the access @param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type. token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are: @param [in] grant_type= (sas_services) Valid values are:
@@ -52,6 +53,7 @@
,inref= ,inref=
,intype=BINARY ,intype=BINARY
,contentdisp=inline ,contentdisp=inline
,ctype=0
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
@@ -103,8 +105,10 @@ filename &fref filesrvc
folderPath="&path" folderPath="&path"
filename="&name" filename="&name"
cdisp="&contentdisp" cdisp="&contentdisp"
%if "&ctype" ne "0" %then %do;
ctype="&ctype"
%end;
lrecl=1048544; lrecl=1048544;
%if &intype=BINARY %then %do; %if &intype=BINARY %then %do;
%mp_binarycopy(inref=&inref, outref=&fref) %mp_binarycopy(inref=&inref, outref=&fref)
%end; %end;

View File

@@ -34,14 +34,25 @@
@param path= The full path (on SAS Drive) where the job will be created @param path= The full path (on SAS Drive) where the job will be created
@param name= The name of the job @param name= The name of the job
@param desc= The description of the job @param desc= (Created by the mv_createjob.sas macro) The job description
@param precode= Space separated list of filerefs, pointing to the code that @param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the job needs to be attached to the beginning of the job
@param code= Fileref(s) of the actual code to be added @param code= (ft15f001) Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token @param access_token_var= (ACCESS_TOKEN) Global macro variable containing the
@param grant_type= valid values are "password" or "authorization_code" access token
(unquoted). The default is authorization_code. @param grant_type= (sas_services) Valid values:
@param replace= select NO to avoid replacing any existing job in that location @li sas_services
@li detect
@li authorization_code
@li password
@param replace= (YES) select NO to avoid replacing any existing job
@param addjesbeginendmacros= (false) Relates to the `_addjesbeginendmacros`
setting. Normally this would always be false however due to a Viya bug
(https://github.com/sasjs/cli/issues/1229) this is now configurable. Valid
values:
@li true
@li false
@li 0 - this will prevent the flag from being set (job will default to true)
@param contextname= Choose a specific context on which to run the Job. Leave @param contextname= Choose a specific context on which to run the Job. Leave
blank to use the default context. From Viya 3.5 it is possible to configure blank to use the default context. From Viya 3.5 it is possible to configure
a shared context - see a shared context - see
@@ -62,6 +73,7 @@ https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5p
,replace=YES ,replace=YES
,debug=0 ,debug=0
,contextname= ,contextname=
,addjesbeginendmacros=false
); );
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -185,19 +197,29 @@ run;
%end; %end;
/* set up the body of the request to create the service */ /* set up the body of the request to create the service */
%local fname3; %local fname3 comma;
%let fname3=%mf_getuniquefileref(); %let fname3=%mf_getuniquefileref();
data _null_; data _null_;
file &fname3 TERMSTR=' '; file &fname3 TERMSTR=' ';
length string $32767; length string $32767;
string=cats('{"version": 0,"name":"' string=cats('{"version": 0,"name":"'
,"&name" ,"&name"
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"' ,'","type":"Compute","parameters":['
,',"type":"CHARACTER","defaultValue":"false"}'); %if &addjesbeginendmacros ne 0 %then %do;
,'{"name":"_addjesbeginendmacros"'
,',"type":"CHARACTER","defaultValue":"'
,"&addjesbeginendmacros"
,'"}'
%let comma=%str(,);
%end;
);
context=quote(cats(symget('contextname'))); context=quote(cats(symget('contextname')));
if context ne '""' then do; if context ne '""' then do;
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":' string=cats(string
,context,',"type":"CHARACTER","label":"Context Name","required": false}'); ,"&comma"
,'{"version": 1,"name": "_contextName","defaultValue":'
,context,',"type":"CHARACTER","label":"Context Name","required": false}'
);
end; end;
string=cats(string,'],"code":"'); string=cats(string,'],"code":"');
put string; put string;

View File

@@ -312,7 +312,7 @@ data _null_;
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 ' /* overwritten when fmt=Y and a custom format exists in catalog */ ';
put ' if typelong=''num'' then call symputx(cats(''fmtlen'',_n_),200,''l''); '; 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 ' else call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+10)*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); ';
@@ -368,15 +368,15 @@ data _null_;
put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); '; put ' %let tmpds4=%substr(col%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql noprint; '; put ' proc sql noprint; ';
put ' create table &tmpds1 as '; put ' create table &tmpds1 as ';
put ' select cats(libname,''.'',memname) as fmtcat, '; put ' select cats(libname,''.'',memname) as FMTCAT, ';
put ' fmtname '; put ' FMTNAME ';
put ' from dictionary.formats '; put ' from dictionary.formats ';
put ' where fmttype=''F'' and libname is not null '; put ' where fmttype=''F'' and libname is not null ';
put ' and fmtname in (select format from &colinfo where format is not null) '; put ' and fmtname in (select format from &colinfo where format is not null) ';
put ' order by 1; '; put ' order by 1; ';
put ' create table &tmpds2( '; put ' create table &tmpds2( ';
put ' FMTNAME char(32), '; put ' FMTNAME char(32), ';
put ' MAX num length=3 '; put ' LENGTH num ';
put ' ); '; put ' ); ';
put ' %local catlist cat fmtlist i; '; put ' %local catlist cat fmtlist i; ';
put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; '; put ' select distinct fmtcat into: catlist separated by '' '' from &tmpds1; ';
@@ -385,16 +385,16 @@ data _null_;
put ' proc sql; '; put ' proc sql; ';
put ' select distinct fmtname into: fmtlist separated by '' '' '; put ' select distinct fmtname into: fmtlist separated by '' '' ';
put ' from &tmpds1 where fmtcat="&cat"; '; put ' from &tmpds1 where fmtcat="&cat"; ';
put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname max); '; put ' proc format lib=&cat cntlout=&tmpds3(keep=fmtname length); ';
put ' select &fmtlist; '; put ' select &fmtlist; ';
put ' run; '; put ' run; ';
put ' proc sql; '; put ' proc sql; ';
put ' insert into &tmpds2 select distinct fmtname,max from &tmpds3; '; put ' insert into &tmpds2 select distinct fmtname,length from &tmpds3; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' create table &tmpds4 as '; put ' create table &tmpds4 as ';
put ' select a.*, b.max as maxw '; put ' select a.*, b.length as MAXW ';
put ' from &colinfo a '; put ' from &colinfo a ';
put ' left join &tmpds2 b '; put ' left join &tmpds2 b ';
put ' on cats(a.format)=cats(upcase(b.fmtname)) '; put ' on cats(a.format)=cats(upcase(b.fmtname)) ';
@@ -405,7 +405,7 @@ data _null_;
put ' call symputx( '; put ' call symputx( ';
put ' cats(''fmtlen'',_n_), '; put ' cats(''fmtlen'',_n_), ';
put ' /* vars need extra padding due to JSON escaping of special chars */ '; put ' /* vars need extra padding due to JSON escaping of special chars */ ';
put ' min(32767,ceil((max(length,maxw)+3)*1.5)) '; put ' min(32767,ceil((max(length,maxw)+10)*1.5)) ';
put ' ,''l'' '; put ' ,''l'' ';
put ' ); '; put ' ); ';
put ' run; '; put ' run; ';
@@ -480,7 +480,7 @@ data _null_;
put ' format _numeric_ bart.; '; put ' format _numeric_ bart.; ';
put ' %do i=1 %to &numcols; '; put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; '; put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; '; put ' if findc(&&name&i,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' &&name&i=''"''!!trim( '; put ' &&name&i=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ '; put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ '; put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
@@ -493,8 +493,9 @@ data _null_;
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ '; put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ '; put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ '; put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))))))))))!!''"''; ';
put ' end; '; put ' end; ';
put ' else &&name&i=quote(cats(&&name&i)); '; put ' else &&name&i=quote(cats(&&name&i)); ';
put ' %end; '; put ' %end; ';
@@ -590,7 +591,7 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,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; ';
@@ -697,8 +698,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; ';
@@ -721,7 +722,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; ';

View File

@@ -35,6 +35,9 @@
`,"$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
@@ -49,7 +52,7 @@
**/ **/
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=N,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;
@@ -156,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;
@@ -180,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;