1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-19 09:34:34 +00:00

Compare commits

..

15 Commits

Author SHA1 Message Date
cc7cc55022 feat: mp_csv2ds macro for importing a CSV using a SAS table to provide a template (eg for lengths / types etc) 2020-11-02 15:44:45 +01:00
15687be5d6 fix: tidy up of SAS flavour DDL 2020-10-30 11:43:15 +01:00
d9a82c0bdf fix: incorrect filepath when using filerefs in mp_dirlist 2020-10-29 12:08:07 +01:00
6f06e5540d feat: adding fileref support for mp_dirlist, as well as a directory column on the output dataset 2020-10-29 11:30:15 +01:00
6b782a4fa2 chore: adding sitemap 2020-10-18 01:00:35 +02:00
efe4709dde chore: formatting in mp_guesspk 2020-10-14 16:42:04 +02:00
5cb41041d9 fix: upcase showlog value in mp_getddl() to allow lowercase user entries 2020-10-13 11:20:30 +02:00
f50cb03fd3 fix: mp_ds2cards was failing when the maxobs was less than the number of variables. SQL maxobs option is now reset. 2020-10-12 18:28:50 +02:00
ac46489f11 fix: enabling mp_abort.sas to work in Viya when useComputeApi is true (and the SYS_JES_JOB_URI is empty) 2020-10-11 00:34:08 +02:00
vrh
5e45701e74 fix: extra debug info in mp_searchdata, as well as named literal support 2020-10-02 22:34:36 +02:00
vrh
8caaacd9f0 docs: comment fix 2020-09-28 09:22:29 +02:00
vrh
91983e0a91 fix: trim edge cases and return of the register client url 2020-09-11 00:38:37 +02:00
vrh
7b72f0ac94 fix: alternative base_uri option on tokenauth macro, also description update for listclients 2020-09-10 09:30:09 +02:00
vrh
3eae34d8b7 fix: adding base_uri in all calls to cover instances where viya calls are not on localhost 2020-09-07 14:01:39 +02:00
vrh
58358c916d chore: doc updates 2020-09-05 17:22:38 +02:00
19 changed files with 465 additions and 166 deletions

248
all.sas
View File

@@ -380,7 +380,7 @@ options noquotelenmax;
@brief Returns the engine type of a SAS library
@details Usage:
%put %mf_getEngine(SASHELP);
%put %mf_getengine(SASHELP);
returns:
> V9
@@ -398,9 +398,10 @@ options noquotelenmax;
@version 9.2
@author Allan Bowe
**/
%macro mf_getEngine(libref
**/ /** \cond */
%macro mf_getengine(libref
)/*/STORE SOURCE*/;
%local dsid engnum rc engine;
@@ -419,7 +420,8 @@ options noquotelenmax;
&engine
%mend;
/**
/** \endcond *//**
@file
@brief Returns the size of a file in bytes.
@details Provide full path/filename.extension to the file, eg:
@@ -1316,13 +1318,23 @@ Usage:
**/
%macro mf_trimstr(basestr,trimstr);
%local trimlen trimval;
%local baselen trimlen trimval;
/* return if basestr is shorter than trimstr (or 0) */
%let baselen=%length(%superq(basestr));
%let trimlen=%length(%superq(trimstr));
%if &baselen < &trimlen or &baselen=0 %then %return;
/* obtain the characters from the end of basestr */
%let trimval=%qsubstr(%superq(basestr)
,%length(%superq(basestr))-&trimlen+1
,&trimlen);
%if %superq(trimval)=%superq(trimstr) %then %do;
/* compare and if matching, chop it off! */
%if %superq(basestr)=%superq(trimstr) %then %do;
%return;
%end;
%else %if %superq(trimval)=%superq(trimstr) %then %do;
%qsubstr(%superq(basestr),1,%length(%superq(basestr))-&trimlen)
%end;
%else %do;
@@ -1476,6 +1488,12 @@ Usage:
results back to the client in an STP Web App context, or completely stop
in the case of a batch run.
Using SAS Abort Cancel mechanisms can cause hung sessions in some Stored Process
environments. This macro takes a unique approach - we set the SAS syscc to 0,
run `stpsrvset('program error', 0)` (if SAS 9) and then - we open a macro
but don't close it! This provides a graceful abort for SAS web services in all
web enabled environments.
@param mac= to contain the name of the calling macro
@param msg= message to be returned
@param iftrue= supply a condition under which the macro should be executed.
@@ -1535,8 +1553,15 @@ Usage:
%end;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json";
/* setup webout */
OPTIONS NOBOMFILE;
%if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
filename _webout temp lrecl=999999 mod;
%end;
%else %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json" lrecl=999999 mod;
%end;
%end;
/* send response in SASjs JSON format */
@@ -1879,6 +1904,113 @@ Usage:
%mend;
/**
@file mp_csv2ds.sas
@brief Efficient import of arbitrary CSV using a dataset as template
@details Used to import relevant columns from a large CSV using
a dataset to provide the types and lengths. Assumes that a header
row is provided, and datarows start on line 2. Extra columns in
both the CSV and base dataset are ignored.
Usage:
filename mycsv temp;
data _null_;
file mycsv;
put 'name,age,nickname';
put 'John,48,Jonny';
put 'Jennifer,23,Jen';
run;
%mp_csv2ds(inref=mycsv,outds=myds,baseds=sashelp.class)
@param inref= fileref to the CSV
@param outds= output ds. Could also be a view (eg `outds=myds/view=myds`)
@param baseds= Template dataset on which to create the input statement.
Is used to determine types, lengths, and any informats.
@version 9.2
@author Allan Bowe
**/
%macro mp_csv2ds(inref=0,outds=0,baseds=0);
%if &inref=0 %then %do;
%put %str(ERR)OR: the INREF variable must be provided;
%let syscc=4;
%abort;
%end;
%if &outds=0 %then %do;
%put %str(ERR)OR: the OUTDS variable must be provided;
%let syscc=4;
%return;
%end;
%if &baseds=0 %then %do;
%put %str(ERR)OR: the BASEDS variable must be provided;
%let syscc=4;
%return;
%end;
/* get the variables in the CSV */
data _data_;
infile &inref;
input;
length name $32;
do i=1 to countc(_infile_,',')+1;
name=upcase(scan(_infile_,i,','));
output;
end;
stop;
run;
%local csv_vars;%let csv_vars=&syslast;
/* get the variables in the dataset */
proc contents noprint data=&baseds
out=_data_ (keep=name type length format: informat);
run;
%local base_vars; %let base_vars=&syslast;
proc sql undo_policy=none;
create table &csv_vars as
select a.*
,b.type
,b.length
,b.format
,b.formatd
,b.formatl
,b.informat
from &csv_vars a
left join &base_vars b
on a.name=upcase(b.name)
order by i;
/* prepare the input statement */
%local instat dropvars;
data _null_;
set &syslast end=last;
length in dropvars $32767;
retain in dropvars;
if missing(type) then do;
informat='$1.';
dropvars=catx(' ',dropvars,name);
end;
else if missing(informat) then do;
if type=1 then informat='best.';
else informat=cats('$',length,'.');
end;
in=catx(' ',in,name,':',informat);
if last then do;
call symputx('instat',in,'l');
call symputx('dropvars',dropvars,'l');
end;
run;
data &outds;
infile &inref dsd firstobs=2;
input &instat;
drop &dropvars;
run;
%mend;/**
@file mp_deleteconstraints.sas
@brief Delete constraionts
@details Takes the output from mp_getconstraints.sas as input
@@ -1951,6 +2083,8 @@ run;
%mp_dirlist(outds=cwdfileprops, getattrs=YES)
%mp_dirlist(fref=MYFREF)
@warning In a Unix environment, the existence of a named pipe will cause this
macro to hang. Therefore this tool should be used with caution in a SAS 9 web
application, as it can use up all available multibridge sessions if requests
@@ -1960,12 +2094,14 @@ run;
@param path= for which to return contents
@param fref= Provide a DISK engine fileref as an alternative to PATH
@param outds= the output dataset to create
@param getattrs= YES/NO (default=NO). Uses doptname and foptname to return
all attributes for each file / folder.
@returns outds contains the following variables:
- directory (containing folder)
- file_or_folder (file / folder)
- filepath (path/to/file.name)
- filename (just the file name)
@@ -1978,18 +2114,26 @@ run;
**/
%macro mp_dirlist(path=%sysfunc(pathname(work))
, fref=0
, outds=work.mp_dirlist
, getattrs=NO
)/*/STORE SOURCE*/;
%let getattrs=%upcase(&getattrs)XX;
data &outds (compress=no keep=file_or_folder filepath filename ext msg);
length filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
data &outds (compress=no keep=file_or_folder filepath filename ext msg directory);
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
%if &fref=0 %then %do;
rc = filename(fref, "&path");
%end;
%else %do;
fref="&fref";
rc=0;
%end;
if rc = 0 then do;
did = dopen(fref);
directory=dinfo(did,'Directory');
if did=0 then do;
putlog "NOTE: This directory is empty - &path";
putlog "NOTE: This directory is empty - " directory;
msg=sysmsg();
put _all_;
stop;
@@ -2004,7 +2148,8 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
dnum = dnum(did);
do i = 1 to dnum;
filename = dread(did, i);
rc = filename(fref2, "&path/"!!filename);
filepath=cats(directory,'/',filename);
rc = filename(fref2,filepath);
midd=dopen(fref2);
dmsg=sysmsg();
if did > 0 then file_or_folder='folder';
@@ -2027,7 +2172,6 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
ext='';
file_or_folder='folder';
end;
filepath="&path/"!!filename;
output;
end;
rc = dclose(did);
@@ -2274,8 +2418,7 @@ proc sql
order by ranuni(42)
%end;
;
reset outobs=max;
create table datalines1 as
select name,type,length,varnum,format,label from dictionary.columns
where libname="%upcase(%scan(&base_ds,1))"
@@ -2505,7 +2648,6 @@ create table &outds as
datetime2 format or regular decimal type
@version 9.3
@author Allan Bowe
@source https://github.com/sasjs/core
**/
%macro mp_getddl(libref,ds,fref=getddl,flavour=SAS,showlog=NO,schema=
@@ -2607,7 +2749,7 @@ run;
%let curds=%scan(&dsnlist,&x);
data _null_;
file &fref mod;
length nm lab $1024;
length nm lab $1024 typ $20;
set &colinfo (where=(upcase(memname)="&curds")) end=last;
if _n_=1 then do;
@@ -2621,10 +2763,12 @@ run;
end;
else put " ,"@@;
if length(format)>1 then fmt=" format="!!cats(format);
len=" length="!!cats(length);
lab=" label="!!quote(trim(label));
if length(label)>1 then lab=" label="!!quote(trim(label));
if notnull='yes' then notnul=' not null';
put name type len fmt notnul lab;
if type='char' then typ=cats('char(',length,')');
else if length ne 8 then typ='num length='!!left(length);
else typ='num';
put name typ fmt notnul lab;
run;
/* Extra step for data constraints */
@@ -2814,7 +2958,7 @@ run;
%end;
%end;
%if &showlog=YES %then %do;
%if %upcase(&showlog)=YES %then %do;
options ps=max;
data _null_;
infile &fref;
@@ -3697,7 +3841,7 @@ proc sort; by descending sumcols memname libname; run;
@brief Searches all data in a library
@details
Scans an entire library and creates a copy of any table
containing a specific string or numeric value. Only
containing a specific string OR numeric value. Only
matching records are written out.
If both a string and numval are provided, the string
will take precedence.
@@ -3738,9 +3882,13 @@ proc sort; by descending sumcols memname libname; run;
,filter_text=%str(1=1)
)/*/STORE SOURCE*/;
%local table_list table table_num table colnum col start_tm vars type coltype;
%local table_list table table_num table colnum col start_tm check_tm vars type coltype;
%put process began at %sysfunc(datetime(),datetime19.);
%if &syscc ge 4 %then %do;
%put %str(WAR)NING: SYSCC=&syscc on macro entry;
%return;
%end;
%if &string = %then %let type=N;
%else %let type=C;
@@ -3772,6 +3920,7 @@ proc sql
%put NO COLUMNS IN &lib..&table! This will be skipped.;
%end;
%else %do;
%let check_tm=%sysfunc(datetime());
/* build sql statement */
create table mpsearch.&table as select * from &lib..&table
where %unquote(&filter_text) and
@@ -3782,14 +3931,19 @@ proc sql
%let coltype=%mf_getvartype(&lib..&table,&col);
%if &type=C and &coltype=C %then %do;
/* if a char column, see if it contains the string */
or (&col ? "&string")
or ("&col"n ? "&string")
%end;
%else %if &type=N and &coltype=N %then %do;
/* if numeric match exactly */
or (&col = &numval)
or ("&col"n = &numval)
%end;
%end;
);
%put Search query for &table took %sysevalf(%sysfunc(datetime())-&check_tm) seconds;
%if &sqlrc ne 0 %then %do;
%put %str(WAR)NING: SQLRC=&sqlrc when processing &table;
%return;
%end;
%if %mf_nobs(mpsearch.&table)=0 %then %do;
drop table mpsearch.&table;
%end;
@@ -10597,7 +10751,7 @@ run;
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='members' then call symputx('mref',quote(trim(href)),'l');
if rel='members' then call symputx('mref',quote("&base_uri"!!trim(href)),'l');
run;
/* get the children */
@@ -10627,7 +10781,7 @@ run;
%put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ;
%return;
%end;
proc http method="DELETE" url="&uri" &oauth_bearer;
proc http method="DELETE" url="&base_uri&uri" &oauth_bearer;
headers
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"
@@ -10886,9 +11040,9 @@ libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='deleteRecursively' then
call symputx('href',quote(trim(href)),'l');
call symputx('href',quote("&base_uri"!!trim(href)),'l');
else if rel='members' then
call symputx('mref',quote(cats(href,'?recursive=true')),'l');
call symputx('mref',quote(cats("&base_uri",href,'?recursive=true')),'l');
run;
/* before we can delete the folder, we need to delete the children */
@@ -10909,7 +11063,7 @@ data _null_;
set &libref1a..items_links;
if href=:'/folders/folders' then return;
if rel='deleteResource' then
call execute('proc http method="DELETE" url='!!quote(trim(href))
call execute('proc http method="DELETE" url='!!quote("&base_uri"!!trim(href))
!!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/');
run;
@@ -10994,8 +11148,8 @@ libname &libref1 clear;
)
%mend;/**
@file mv_getgroups.sas
@brief Creates a dataset with a list of viya groups
@file mv_getclients.sas
@brief Get a list of Viya Clients
@details First, be sure you have an access token (which requires an app token).
Using the macros here:
@@ -11015,7 +11169,7 @@ libname &libref1 clear;
Now we can run the macro!
%mv_getgroups()
%mv_getclients()
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
@@ -11160,7 +11314,7 @@ options noquotelenmax;
%if "&root"="/" %then %do;
/* if root just list root folders */
proc http method='GET' out=&fname1 &oauth_bearer
url='%sysfunc(getoption(servicesbaseurl))/folders/rootFolders';
url="&base_uri/folders/rootFolders";
%if &grant_type=authorization_code %then %do;
headers "Authorization"="Bearer &&&access_token_var";
%end;
@@ -11183,7 +11337,7 @@ options noquotelenmax;
/* now get the followon link to list members */
data _null_;
set &libref1..links;
if rel='members' then call symputx('href',quote(trim(href)),'l');
if rel='members' then call symputx('href',quote("&base_uri"!!trim(href)),'l');
run;
%local fname2 libref2;
%let fname2=%mf_getuniquefileref();
@@ -11446,24 +11600,15 @@ libname &libref1 clear;
%mend;/**
@file mv_getusergroups.sas
@brief Creates a dataset with a list of groups for a particular user
@details First, be sure you have an access token (which requires an app token).
@details If using outside of Viya SPRE, then an access token is needed.
Using the macros here:
Compile the macros here:
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
An administrator needs to set you up with an access code:
%mv_registerclient(outds=client)
Navigate to the url from the log (opting in to the groups) and paste the
access code below:
%mv_tokenauth(inds=client,code=wKDZYTEPK6)
Now we can run the macro!
Then run the macro!
%mv_getusergroups(&sysuserid,outds=users)
@@ -11849,7 +11994,7 @@ run;
%end;
/* prepare url */
%if &grant_type=authorization_code %then %do;
%if %index(%superq(grant_type),authorization_code) %then %do;
data _null_;
if symexist('_baseurl') then do;
url=symget('_baseurl');
@@ -11868,7 +12013,7 @@ run;
%put CLIENT_SECRET=&client_secret;
%put GRANT_TYPE=&grant_type;
%put;
%if &grant_type=authorization_code %then %do;
%if %index(%superq(grant_type),authorization_code) %then %do;
/* cannot use base_uri here as it includes the protocol which may be incorrect externally */
%put NOTE: The developer must also register below and select 'openid' to get the grant code:;
%put NOTE- ;
@@ -11935,6 +12080,7 @@ libname &libref clear;
@param pass= If grant_type=password then provide the password here
@param access_token_var= The global macro variable to contain the access token
@param refresh_token_var= The global macro variable to contain the refresh token
@param base_uri= The Viya API server location
@version VIYA V.03.04
@author Allan Bowe
@@ -11959,6 +12105,7 @@ libname &libref clear;
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
,base_uri=#NOTSET#
);
%global &access_token_var &refresh_token_var;
@@ -12005,8 +12152,7 @@ run;
/**
* Request access token
*/
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%if &base_uri=#NOTSET# %then %let base_uri=%mf_getplatform(VIYARESTAPI);
%let fref2=%mf_getuniquefileref();
proc http method='POST' in=&grantstring out=&fref2

View File

@@ -3,7 +3,7 @@
@brief Returns the engine type of a SAS library
@details Usage:
%put %mf_getEngine(SASHELP);
%put %mf_getengine(SASHELP);
returns:
> V9
@@ -21,9 +21,10 @@
@version 9.2
@author Allan Bowe
**/
%macro mf_getEngine(libref
**/ /** \cond */
%macro mf_getengine(libref
)/*/STORE SOURCE*/;
%local dsid engnum rc engine;
@@ -42,3 +43,5 @@
&engine
%mend;
/** \endcond */

View File

@@ -23,13 +23,23 @@
**/
%macro mf_trimstr(basestr,trimstr);
%local trimlen trimval;
%local baselen trimlen trimval;
/* return if basestr is shorter than trimstr (or 0) */
%let baselen=%length(%superq(basestr));
%let trimlen=%length(%superq(trimstr));
%if &baselen < &trimlen or &baselen=0 %then %return;
/* obtain the characters from the end of basestr */
%let trimval=%qsubstr(%superq(basestr)
,%length(%superq(basestr))-&trimlen+1
,&trimlen);
%if %superq(trimval)=%superq(trimstr) %then %do;
/* compare and if matching, chop it off! */
%if %superq(basestr)=%superq(trimstr) %then %do;
%return;
%end;
%else %if %superq(trimval)=%superq(trimstr) %then %do;
%qsubstr(%superq(basestr),1,%length(%superq(basestr))-&trimlen)
%end;
%else %do;

View File

@@ -6,6 +6,12 @@
results back to the client in an STP Web App context, or completely stop
in the case of a batch run.
Using SAS Abort Cancel mechanisms can cause hung sessions in some Stored Process
environments. This macro takes a unique approach - we set the SAS syscc to 0,
run `stpsrvset('program error', 0)` (if SAS 9) and then - we open a macro
but don't close it! This provides a graceful abort for SAS web services in all
web enabled environments.
@param mac= to contain the name of the calling macro
@param msg= message to be returned
@param iftrue= supply a condition under which the macro should be executed.
@@ -65,8 +71,15 @@
%end;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json";
/* setup webout */
OPTIONS NOBOMFILE;
%if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
filename _webout temp lrecl=999999 mod;
%end;
%else %do;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json" lrecl=999999 mod;
%end;
%end;
/* send response in SASjs JSON format */

109
base/mp_csv2ds.sas Normal file
View File

@@ -0,0 +1,109 @@
/**
@file mp_csv2ds.sas
@brief Efficient import of arbitrary CSV using a dataset as template
@details Used to import relevant columns from a large CSV using
a dataset to provide the types and lengths. Assumes that a header
row is provided, and datarows start on line 2. Extra columns in
both the CSV and base dataset are ignored.
Usage:
filename mycsv temp;
data _null_;
file mycsv;
put 'name,age,nickname';
put 'John,48,Jonny';
put 'Jennifer,23,Jen';
run;
%mp_csv2ds(inref=mycsv,outds=myds,baseds=sashelp.class)
@param inref= fileref to the CSV
@param outds= output ds. Could also be a view (eg `outds=myds/view=myds`)
@param baseds= Template dataset on which to create the input statement.
Is used to determine types, lengths, and any informats.
@version 9.2
@author Allan Bowe
**/
%macro mp_csv2ds(inref=0,outds=0,baseds=0);
%if &inref=0 %then %do;
%put %str(ERR)OR: the INREF variable must be provided;
%let syscc=4;
%abort;
%end;
%if &outds=0 %then %do;
%put %str(ERR)OR: the OUTDS variable must be provided;
%let syscc=4;
%return;
%end;
%if &baseds=0 %then %do;
%put %str(ERR)OR: the BASEDS variable must be provided;
%let syscc=4;
%return;
%end;
/* get the variables in the CSV */
data _data_;
infile &inref;
input;
length name $32;
do i=1 to countc(_infile_,',')+1;
name=upcase(scan(_infile_,i,','));
output;
end;
stop;
run;
%local csv_vars;%let csv_vars=&syslast;
/* get the variables in the dataset */
proc contents noprint data=&baseds
out=_data_ (keep=name type length format: informat);
run;
%local base_vars; %let base_vars=&syslast;
proc sql undo_policy=none;
create table &csv_vars as
select a.*
,b.type
,b.length
,b.format
,b.formatd
,b.formatl
,b.informat
from &csv_vars a
left join &base_vars b
on a.name=upcase(b.name)
order by i;
/* prepare the input statement */
%local instat dropvars;
data _null_;
set &syslast end=last;
length in dropvars $32767;
retain in dropvars;
if missing(type) then do;
informat='$1.';
dropvars=catx(' ',dropvars,name);
end;
else if missing(informat) then do;
if type=1 then informat='best.';
else informat=cats('$',length,'.');
end;
in=catx(' ',in,name,':',informat);
if last then do;
call symputx('instat',in,'l');
call symputx('dropvars',dropvars,'l');
end;
run;
/* import the CSV */
data &outds;
infile &inref dsd firstobs=2;
input &instat;
drop &dropvars;
run;
%mend;

View File

@@ -20,6 +20,8 @@
%mp_dirlist(outds=cwdfileprops, getattrs=YES)
%mp_dirlist(fref=MYFREF)
@warning In a Unix environment, the existence of a named pipe will cause this
macro to hang. Therefore this tool should be used with caution in a SAS 9 web
application, as it can use up all available multibridge sessions if requests
@@ -29,12 +31,14 @@
@param path= for which to return contents
@param fref= Provide a DISK engine fileref as an alternative to PATH
@param outds= the output dataset to create
@param getattrs= YES/NO (default=NO). Uses doptname and foptname to return
all attributes for each file / folder.
@returns outds contains the following variables:
- directory (containing folder)
- file_or_folder (file / folder)
- filepath (path/to/file.name)
- filename (just the file name)
@@ -47,18 +51,26 @@
**/
%macro mp_dirlist(path=%sysfunc(pathname(work))
, fref=0
, outds=work.mp_dirlist
, getattrs=NO
)/*/STORE SOURCE*/;
%let getattrs=%upcase(&getattrs)XX;
data &outds (compress=no keep=file_or_folder filepath filename ext msg);
length filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
data &outds (compress=no keep=file_or_folder filepath filename ext msg directory);
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200;
%if &fref=0 %then %do;
rc = filename(fref, "&path");
%end;
%else %do;
fref="&fref";
rc=0;
%end;
if rc = 0 then do;
did = dopen(fref);
directory=dinfo(did,'Directory');
if did=0 then do;
putlog "NOTE: This directory is empty - &path";
putlog "NOTE: This directory is empty - " directory;
msg=sysmsg();
put _all_;
stop;
@@ -73,7 +85,8 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
dnum = dnum(did);
do i = 1 to dnum;
filename = dread(did, i);
rc = filename(fref2, "&path/"!!filename);
filepath=cats(directory,'/',filename);
rc = filename(fref2,filepath);
midd=dopen(fref2);
dmsg=sysmsg();
if did > 0 then file_or_folder='folder';
@@ -96,7 +109,6 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
ext='';
file_or_folder='folder';
end;
filepath="&path/"!!filename;
output;
end;
rc = dclose(did);

View File

@@ -103,8 +103,7 @@ proc sql
order by ranuni(42)
%end;
;
reset outobs=max;
create table datalines1 as
select name,type,length,varnum,format,label from dictionary.columns
where libname="%upcase(%scan(&base_ds,1))"

View File

@@ -30,7 +30,6 @@
datetime2 format or regular decimal type
@version 9.3
@author Allan Bowe
@source https://github.com/sasjs/core
**/
%macro mp_getddl(libref,ds,fref=getddl,flavour=SAS,showlog=NO,schema=
@@ -132,7 +131,7 @@ run;
%let curds=%scan(&dsnlist,&x);
data _null_;
file &fref mod;
length nm lab $1024;
length nm lab $1024 typ $20;
set &colinfo (where=(upcase(memname)="&curds")) end=last;
if _n_=1 then do;
@@ -146,10 +145,12 @@ run;
end;
else put " ,"@@;
if length(format)>1 then fmt=" format="!!cats(format);
len=" length="!!cats(length);
lab=" label="!!quote(trim(label));
if length(label)>1 then lab=" label="!!quote(trim(label));
if notnull='yes' then notnul=' not null';
put name type len fmt notnul lab;
if type='char' then typ=cats('char(',length,')');
else if length ne 8 then typ='num length='!!left(length);
else typ='num';
put name typ fmt notnul lab;
run;
/* Extra step for data constraints */
@@ -339,7 +340,7 @@ run;
%end;
%end;
%if &showlog=YES %then %do;
%if %upcase(&showlog)=YES %then %do;
options ps=max;
data _null_;
infile &fref;

View File

@@ -3,7 +3,7 @@
@brief Searches all data in a library
@details
Scans an entire library and creates a copy of any table
containing a specific string or numeric value. Only
containing a specific string OR numeric value. Only
matching records are written out.
If both a string and numval are provided, the string
will take precedence.
@@ -44,9 +44,13 @@
,filter_text=%str(1=1)
)/*/STORE SOURCE*/;
%local table_list table table_num table colnum col start_tm vars type coltype;
%local table_list table table_num table colnum col start_tm check_tm vars type coltype;
%put process began at %sysfunc(datetime(),datetime19.);
%if &syscc ge 4 %then %do;
%put %str(WAR)NING: SYSCC=&syscc on macro entry;
%return;
%end;
%if &string = %then %let type=N;
%else %let type=C;
@@ -78,6 +82,7 @@ proc sql
%put NO COLUMNS IN &lib..&table! This will be skipped.;
%end;
%else %do;
%let check_tm=%sysfunc(datetime());
/* build sql statement */
create table mpsearch.&table as select * from &lib..&table
where %unquote(&filter_text) and
@@ -88,14 +93,19 @@ proc sql
%let coltype=%mf_getvartype(&lib..&table,&col);
%if &type=C and &coltype=C %then %do;
/* if a char column, see if it contains the string */
or (&col ? "&string")
or ("&col"n ? "&string")
%end;
%else %if &type=N and &coltype=N %then %do;
/* if numeric match exactly */
or (&col = &numval)
or ("&col"n = &numval)
%end;
%end;
);
%put Search query for &table took %sysevalf(%sysfunc(datetime())-&check_tm) seconds;
%if &sqlrc ne 0 %then %do;
%put %str(WAR)NING: SQLRC=&sqlrc when processing &table;
%return;
%end;
%if %mf_nobs(mpsearch.&table)=0 %then %do;
drop table mpsearch.&table;
%end;

View File

@@ -16,7 +16,7 @@
<tab type="classmembers" visible="no" title="" intro=""/>
</tab>
<tab type="filelist" visible="yes" title="" intro="List of Files Used in the Macro Core Library"/>
<tab type="filelist" visible="yes" title="" intro="List of Files Used in the Macro-Core Library"/>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>

View File

@@ -36,5 +36,9 @@ echo 'core.sasjs.io' > CNAME
git add *
git commit -m "build.sh build on $(date +%F:%H:%M:%S)"
git push
npx sitemap-generator-cli https://core.sasjs.io
git add *
git commit -m "adding sitemap"
git push
echo "check it out: https://sasjs.github.io/core.github.io/files.html"

View File

@@ -98,7 +98,7 @@ run;
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='members' then call symputx('mref',quote(trim(href)),'l');
if rel='members' then call symputx('mref',quote("&base_uri"!!trim(href)),'l');
run;
/* get the children */
@@ -128,7 +128,7 @@ run;
%put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ;
%return;
%end;
proc http method="DELETE" url="&uri" &oauth_bearer;
proc http method="DELETE" url="&base_uri&uri" &oauth_bearer;
headers
%if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var"

View File

@@ -88,9 +88,9 @@ libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='deleteRecursively' then
call symputx('href',quote(trim(href)),'l');
call symputx('href',quote("&base_uri"!!trim(href)),'l');
else if rel='members' then
call symputx('mref',quote(cats(href,'?recursive=true')),'l');
call symputx('mref',quote(cats("&base_uri",href,'?recursive=true')),'l');
run;
/* before we can delete the folder, we need to delete the children */
@@ -111,7 +111,7 @@ data _null_;
set &libref1a..items_links;
if href=:'/folders/folders' then return;
if rel='deleteResource' then
call execute('proc http method="DELETE" url='!!quote(trim(href))
call execute('proc http method="DELETE" url='!!quote("&base_uri"!!trim(href))
!!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/');
run;

View File

@@ -1,6 +1,6 @@
/**
@file mv_getgroups.sas
@brief Creates a dataset with a list of viya groups
@file mv_getclients.sas
@brief Get a list of Viya Clients
@details First, be sure you have an access token (which requires an app token).
Using the macros here:
@@ -20,7 +20,7 @@
Now we can run the macro!
%mv_getgroups()
%mv_getclients()
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).

View File

@@ -64,7 +64,7 @@ options noquotelenmax;
%if "&root"="/" %then %do;
/* if root just list root folders */
proc http method='GET' out=&fname1 &oauth_bearer
url='%sysfunc(getoption(servicesbaseurl))/folders/rootFolders';
url="&base_uri/folders/rootFolders";
%if &grant_type=authorization_code %then %do;
headers "Authorization"="Bearer &&&access_token_var";
%end;
@@ -87,7 +87,7 @@ options noquotelenmax;
/* now get the followon link to list members */
data _null_;
set &libref1..links;
if rel='members' then call symputx('href',quote(trim(href)),'l');
if rel='members' then call symputx('href',quote("&base_uri"!!trim(href)),'l');
run;
%local fname2 libref2;
%let fname2=%mf_getuniquefileref();

View File

@@ -1,24 +1,15 @@
/**
@file mv_getusergroups.sas
@brief Creates a dataset with a list of groups for a particular user
@details First, be sure you have an access token (which requires an app token).
@details If using outside of Viya SPRE, then an access token is needed.
Using the macros here:
Compile the macros here:
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
An administrator needs to set you up with an access code:
%mv_registerclient(outds=client)
Navigate to the url from the log (opting in to the groups) and paste the
access code below:
%mv_tokenauth(inds=client,code=wKDZYTEPK6)
Now we can run the macro!
Then run the macro!
%mv_getusergroups(&sysuserid,outds=users)

View File

@@ -187,7 +187,7 @@ run;
%end;
/* prepare url */
%if &grant_type=authorization_code %then %do;
%if %index(%superq(grant_type),authorization_code) %then %do;
data _null_;
if symexist('_baseurl') then do;
url=symget('_baseurl');
@@ -206,7 +206,7 @@ run;
%put CLIENT_SECRET=&client_secret;
%put GRANT_TYPE=&grant_type;
%put;
%if &grant_type=authorization_code %then %do;
%if %index(%superq(grant_type),authorization_code) %then %do;
/* cannot use base_uri here as it includes the protocol which may be incorrect externally */
%put NOTE: The developer must also register below and select 'openid' to get the grant code:;
%put NOTE- ;

View File

@@ -38,6 +38,7 @@
@param pass= If grant_type=password then provide the password here
@param access_token_var= The global macro variable to contain the access token
@param refresh_token_var= The global macro variable to contain the refresh token
@param base_uri= The Viya API server location
@version VIYA V.03.04
@author Allan Bowe
@@ -62,6 +63,7 @@
,pass=
,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN
,base_uri=#NOTSET#
);
%global &access_token_var &refresh_token_var;
@@ -108,8 +110,7 @@ run;
/**
* Request access token
*/
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%if &base_uri=#NOTSET# %then %let base_uri=%mf_getplatform(VIYARESTAPI);
%let fref2=%mf_getuniquefileref();
proc http method='POST' in=&grantstring out=&fref2