1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-10 02:40:05 +00:00

Compare commits

...

14 Commits

Author SHA1 Message Date
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
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
10 changed files with 485 additions and 93 deletions

View File

@@ -78,7 +78,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

263
all.sas
View File

@@ -5826,6 +5826,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 +8819,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 +8903,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 +8959,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 +8976,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 +8996,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 +9071,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 +9084,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 +15399,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 +15455,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 +15472,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 +15492,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 +15567,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 +15580,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; ';
@@ -17659,6 +17771,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
@@ -20242,7 +20421,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); ';
@@ -20298,15 +20477,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; ';
@@ -20315,16 +20494,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)) ';
@@ -20335,7 +20514,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; ';
@@ -20410,7 +20589,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 */ ';
@@ -20423,8 +20602,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; ';
@@ -22705,7 +22885,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); ';
@@ -22761,15 +22941,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; ';
@@ -22778,16 +22958,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)) ';
@@ -22798,7 +22978,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; ';
@@ -22873,7 +23053,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 */ ';
@@ -22886,8 +23066,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; ';

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; ';

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

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

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

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