1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-12 15:04:36 +00:00

Compare commits

...

21 Commits

Author SHA1 Message Date
abccafab7b feat: adding filref option to mp_streamfile.sas 2020-11-16 11:08:01 +01:00
f6cec012da fix: removing unnecessary cond flags in mf_abort, adding abort logic in mp_csv2ds 2020-11-08 22:04:25 +01:00
d51be73017 fix: macro param and extra log info in mp_csv2ds 2020-11-03 09:43:47 +01:00
cafffbb509 fix: adding a period to enable formats such as anydtdtme 2020-11-02 17:26:59 +01:00
a88efacfab fix: making view an option so that existence can be checked for 2020-11-02 17:15:29 +01:00
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
vrh
578ef26cd5 fix: support for tab characters, closes https://github.com/macropeople/macrocore/issues/21 2020-09-04 09:51:11 +02:00
23 changed files with 564 additions and 178 deletions

294
all.sas
View File

@@ -380,7 +380,7 @@ options noquotelenmax;
@brief Returns the engine type of a SAS library @brief Returns the engine type of a SAS library
@details Usage: @details Usage:
%put %mf_getEngine(SASHELP); %put %mf_getengine(SASHELP);
returns: returns:
> V9 > V9
@@ -398,9 +398,10 @@ options noquotelenmax;
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getEngine(libref %macro mf_getengine(libref
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local dsid engnum rc engine; %local dsid engnum rc engine;
@@ -418,8 +419,7 @@ options noquotelenmax;
&engine &engine
%mend; %mend;/**
/**
@file @file
@brief Returns the size of a file in bytes. @brief Returns the size of a file in bytes.
@details Provide full path/filename.extension to the file, eg: @details Provide full path/filename.extension to the file, eg:
@@ -1316,13 +1316,23 @@ Usage:
**/ **/
%macro mf_trimstr(basestr,trimstr); %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)); %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) %let trimval=%qsubstr(%superq(basestr)
,%length(%superq(basestr))-&trimlen+1 ,%length(%superq(basestr))-&trimlen+1
,&trimlen); ,&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) %qsubstr(%superq(basestr),1,%length(%superq(basestr))-&trimlen)
%end; %end;
%else %do; %else %do;
@@ -1476,6 +1486,12 @@ Usage:
results back to the client in an STP Web App context, or completely stop results back to the client in an STP Web App context, or completely stop
in the case of a batch run. 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 mac= to contain the name of the calling macro
@param msg= message to be returned @param msg= message to be returned
@param iftrue= supply a condition under which the macro should be executed. @param iftrue= supply a condition under which the macro should be executed.
@@ -1535,8 +1551,15 @@ Usage:
%end; %end;
%if %symexist(SYS_JES_JOB_URI) %then %do; %if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */ /* setup webout */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"; 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; %end;
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
@@ -1879,6 +1902,149 @@ Usage:
%mend; %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 (lib.ds format)
@param view= Set to YES or NO to determine whether the output should be
a view or not. Default is NO (not a view).
@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
<h4> Dependencies </h4>
@li mp_abort.sas
@li mf_existds.sas
**/
%macro mp_csv2ds(inref=0,outds=0,baseds=0,view=NO);
%mp_abort(iftrue=( &inref=0 )
,mac=&sysmacroname
,msg=%str(the INREF variable must be provided)
)
%mp_abort(iftrue=( %superq(outds)=0 )
,mac=&sysmacroname
,msg=%str(the OUTDS variable must be provided)
)
%mp_abort(iftrue=( &baseds=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS variable must be provided)
)
%mp_abort(iftrue=( &baseds=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS variable must be provided)
)
%mp_abort(iftrue=( %mf_existds(&baseds)=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS dataset (&baseds) needs to be assigned, and to exist)
)
/* count rows */
%local hasheader; %let hasheader=0;
data _null_;
if _N_ > 1 then do;
call symputx('hasheader',1,'l');
stop;
end;
infile &inref;
input;
run;
%mp_abort(iftrue=( &hasheader=0 )
,mac=&sysmacroname
,msg=%str(No header row in &inref)
)
/* 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;
else informat=cats(informat,'.');
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
%if %upcase(&view)=YES %then %do;
/view=&outds
%end;
;
infile &inref dsd firstobs=2;
input &instat;
%if %length(&dropvars)>0 %then %do;
drop &dropvars;
%end;
run;
%mend;/**
@file mp_deleteconstraints.sas @file mp_deleteconstraints.sas
@brief Delete constraionts @brief Delete constraionts
@details Takes the output from mp_getconstraints.sas as input @details Takes the output from mp_getconstraints.sas as input
@@ -1951,6 +2117,8 @@ run;
%mp_dirlist(outds=cwdfileprops, getattrs=YES) %mp_dirlist(outds=cwdfileprops, getattrs=YES)
%mp_dirlist(fref=MYFREF)
@warning In a Unix environment, the existence of a named pipe will cause this @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 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 application, as it can use up all available multibridge sessions if requests
@@ -1960,12 +2128,14 @@ run;
@param path= for which to return contents @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 outds= the output dataset to create
@param getattrs= YES/NO (default=NO). Uses doptname and foptname to return @param getattrs= YES/NO (default=NO). Uses doptname and foptname to return
all attributes for each file / folder. all attributes for each file / folder.
@returns outds contains the following variables: @returns outds contains the following variables:
- directory (containing folder)
- file_or_folder (file / folder) - file_or_folder (file / folder)
- filepath (path/to/file.name) - filepath (path/to/file.name)
- filename (just the file name) - filename (just the file name)
@@ -1978,18 +2148,26 @@ run;
**/ **/
%macro mp_dirlist(path=%sysfunc(pathname(work)) %macro mp_dirlist(path=%sysfunc(pathname(work))
, fref=0
, outds=work.mp_dirlist , outds=work.mp_dirlist
, getattrs=NO , getattrs=NO
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let getattrs=%upcase(&getattrs)XX; %let getattrs=%upcase(&getattrs)XX;
data &outds (compress=no keep=file_or_folder filepath filename ext msg); data &outds (compress=no keep=file_or_folder filepath filename ext msg directory);
length filepath $500 fref fref2 $8 file_or_folder $6 filename $80 ext $20 msg $200; 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"); rc = filename(fref, "&path");
%end;
%else %do;
fref="&fref";
rc=0;
%end;
if rc = 0 then do; if rc = 0 then do;
did = dopen(fref); did = dopen(fref);
directory=dinfo(did,'Directory');
if did=0 then do; if did=0 then do;
putlog "NOTE: This directory is empty - &path"; putlog "NOTE: This directory is empty - " directory;
msg=sysmsg(); msg=sysmsg();
put _all_; put _all_;
stop; stop;
@@ -2004,7 +2182,8 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
dnum = dnum(did); dnum = dnum(did);
do i = 1 to dnum; do i = 1 to dnum;
filename = dread(did, i); filename = dread(did, i);
rc = filename(fref2, "&path/"!!filename); filepath=cats(directory,'/',filename);
rc = filename(fref2,filepath);
midd=dopen(fref2); midd=dopen(fref2);
dmsg=sysmsg(); dmsg=sysmsg();
if did > 0 then file_or_folder='folder'; if did > 0 then file_or_folder='folder';
@@ -2027,7 +2206,6 @@ data &outds (compress=no keep=file_or_folder filepath filename ext msg);
ext=''; ext='';
file_or_folder='folder'; file_or_folder='folder';
end; end;
filepath="&path/"!!filename;
output; output;
end; end;
rc = dclose(did); rc = dclose(did);
@@ -2274,8 +2452,7 @@ proc sql
order by ranuni(42) order by ranuni(42)
%end; %end;
; ;
reset outobs=max;
create table datalines1 as create table datalines1 as
select name,type,length,varnum,format,label from dictionary.columns select name,type,length,varnum,format,label from dictionary.columns
where libname="%upcase(%scan(&base_ds,1))" where libname="%upcase(%scan(&base_ds,1))"
@@ -2505,7 +2682,6 @@ create table &outds as
datetime2 format or regular decimal type datetime2 format or regular decimal type
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
@source https://github.com/sasjs/core
**/ **/
%macro mp_getddl(libref,ds,fref=getddl,flavour=SAS,showlog=NO,schema= %macro mp_getddl(libref,ds,fref=getddl,flavour=SAS,showlog=NO,schema=
@@ -2607,7 +2783,7 @@ run;
%let curds=%scan(&dsnlist,&x); %let curds=%scan(&dsnlist,&x);
data _null_; data _null_;
file &fref mod; file &fref mod;
length nm lab $1024; length nm lab $1024 typ $20;
set &colinfo (where=(upcase(memname)="&curds")) end=last; set &colinfo (where=(upcase(memname)="&curds")) end=last;
if _n_=1 then do; if _n_=1 then do;
@@ -2621,10 +2797,12 @@ run;
end; end;
else put " ,"@@; else put " ,"@@;
if length(format)>1 then fmt=" format="!!cats(format); if length(format)>1 then fmt=" format="!!cats(format);
len=" length="!!cats(length); if length(label)>1 then lab=" label="!!quote(trim(label));
lab=" label="!!quote(trim(label));
if notnull='yes' then notnul=' not null'; 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; run;
/* Extra step for data constraints */ /* Extra step for data constraints */
@@ -2814,7 +2992,7 @@ run;
%end; %end;
%end; %end;
%if &showlog=YES %then %do; %if %upcase(&showlog)=YES %then %do;
options ps=max; options ps=max;
data _null_; data _null_;
infile &fref; infile &fref;
@@ -3697,7 +3875,7 @@ proc sort; by descending sumcols memname libname; run;
@brief Searches all data in a library @brief Searches all data in a library
@details @details
Scans an entire library and creates a copy of any table 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. matching records are written out.
If both a string and numval are provided, the string If both a string and numval are provided, the string
will take precedence. will take precedence.
@@ -3738,9 +3916,13 @@ proc sort; by descending sumcols memname libname; run;
,filter_text=%str(1=1) ,filter_text=%str(1=1)
)/*/STORE SOURCE*/; )/*/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.); %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; %if &string = %then %let type=N;
%else %let type=C; %else %let type=C;
@@ -3772,6 +3954,7 @@ proc sql
%put NO COLUMNS IN &lib..&table! This will be skipped.; %put NO COLUMNS IN &lib..&table! This will be skipped.;
%end; %end;
%else %do; %else %do;
%let check_tm=%sysfunc(datetime());
/* build sql statement */ /* build sql statement */
create table mpsearch.&table as select * from &lib..&table create table mpsearch.&table as select * from &lib..&table
where %unquote(&filter_text) and where %unquote(&filter_text) and
@@ -3782,14 +3965,19 @@ proc sql
%let coltype=%mf_getvartype(&lib..&table,&col); %let coltype=%mf_getvartype(&lib..&table,&col);
%if &type=C and &coltype=C %then %do; %if &type=C and &coltype=C %then %do;
/* if a char column, see if it contains the string */ /* if a char column, see if it contains the string */
or (&col ? "&string") or ("&col"n ? "&string")
%end; %end;
%else %if &type=N and &coltype=N %then %do; %else %if &type=N and &coltype=N %then %do;
/* if numeric match exactly */ /* if numeric match exactly */
or (&col = &numval) or ("&col"n = &numval)
%end; %end;
%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; %if %mf_nobs(mpsearch.&table)=0 %then %do;
drop table mpsearch.&table; drop table mpsearch.&table;
%end; %end;
@@ -3923,7 +4111,7 @@ proc sql
options &etls_syntaxcheck; options &etls_syntaxcheck;
%mend;/** %mend;/**
@file mp_streamfile.sas @file
@brief Streams a file to _webout according to content type @brief Streams a file to _webout according to content type
@details Will set headers using appropriate functions (SAS 9 vs Viya) and send @details Will set headers using appropriate functions (SAS 9 vs Viya) and send
content as a binary stream. content as a binary stream.
@@ -3941,6 +4129,7 @@ proc sql
@param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT) @param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT)
@param inloc= /path/to/file.ext to be sent @param inloc= /path/to/file.ext to be sent
@param inref= fileref of file to be sent (if provided, overrides `inloc`)
@param outname= the name of the file, as downloaded by the browser @param outname= the name of the file, as downloaded by the browser
@author Allan Bowe @author Allan Bowe
@@ -3951,6 +4140,7 @@ proc sql
%macro mp_streamfile( %macro mp_streamfile(
contenttype=TEXT contenttype=TEXT
,inloc= ,inloc=
,inref=0
,outname= ,outname=
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -4034,7 +4224,12 @@ proc sql
%return; %return;
%end; %end;
%if &inref ne 0 %then %do;
%mp_binarycopy(inref=&inref,outref=_webout)
%end;
%else %do;
%mp_binarycopy(inloc="&inloc",outref=_webout) %mp_binarycopy(inloc="&inloc",outref=_webout)
%end;
%mend;/** %mend;/**
@file mp_unzip.sas @file mp_unzip.sas
@@ -7082,6 +7277,7 @@ data _null_;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "WARNING: missing value for " entity=; otherwise putlog "WARNING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));
@@ -7996,6 +8192,7 @@ data _null_;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "%str(WARN)ING: missing value for " entity=; otherwise putlog "%str(WARN)ING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));
@@ -8630,6 +8827,7 @@ run;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "WARNING: missing value for " entity=; otherwise putlog "WARNING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));
@@ -10594,7 +10792,7 @@ run;
libname &libref1 JSON fileref=&fname1; libname &libref1 JSON fileref=&fname1;
data _null_; data _null_;
set &libref1..links; 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; run;
/* get the children */ /* get the children */
@@ -10624,7 +10822,7 @@ run;
%put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ; %put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ;
%return; %return;
%end; %end;
proc http method="DELETE" url="&uri" &oauth_bearer; proc http method="DELETE" url="&base_uri&uri" &oauth_bearer;
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var" "Authorization"="Bearer &&&access_token_var"
@@ -10883,9 +11081,9 @@ libname &libref1 JSON fileref=&fname1;
data _null_; data _null_;
set &libref1..links; set &libref1..links;
if rel='deleteRecursively' then 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 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; run;
/* before we can delete the folder, we need to delete the children */ /* before we can delete the folder, we need to delete the children */
@@ -10906,7 +11104,7 @@ data _null_;
set &libref1a..items_links; set &libref1a..items_links;
if href=:'/folders/folders' then return; if href=:'/folders/folders' then return;
if rel='deleteResource' then 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" ' !!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/'); !!' "Accept"="*/*";run; /**/');
run; run;
@@ -10991,8 +11189,8 @@ libname &libref1 clear;
) )
%mend;/** %mend;/**
@file mv_getgroups.sas @file mv_getclients.sas
@brief Creates a dataset with a list of viya groups @brief Get a list of Viya Clients
@details First, be sure you have an access token (which requires an app token). @details First, be sure you have an access token (which requires an app token).
Using the macros here: Using the macros here:
@@ -11012,7 +11210,7 @@ libname &libref1 clear;
Now we can run the macro! Now we can run the macro!
%mv_getgroups() %mv_getclients()
@param access_token_var= The global macro variable to contain the access token @param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted). @param grant_type= valid values are "password" or "authorization_code" (unquoted).
@@ -11157,7 +11355,7 @@ options noquotelenmax;
%if "&root"="/" %then %do; %if "&root"="/" %then %do;
/* if root just list root folders */ /* if root just list root folders */
proc http method='GET' out=&fname1 &oauth_bearer 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; %if &grant_type=authorization_code %then %do;
headers "Authorization"="Bearer &&&access_token_var"; headers "Authorization"="Bearer &&&access_token_var";
%end; %end;
@@ -11180,7 +11378,7 @@ options noquotelenmax;
/* now get the followon link to list members */ /* now get the followon link to list members */
data _null_; data _null_;
set &libref1..links; 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; run;
%local fname2 libref2; %local fname2 libref2;
%let fname2=%mf_getuniquefileref(); %let fname2=%mf_getuniquefileref();
@@ -11443,24 +11641,15 @@ libname &libref1 clear;
%mend;/** %mend;/**
@file mv_getusergroups.sas @file mv_getusergroups.sas
@brief Creates a dataset with a list of groups for a particular user @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 filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas"; "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc; %inc mc;
An administrator needs to set you up with an access code: Then run the macro!
%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!
%mv_getusergroups(&sysuserid,outds=users) %mv_getusergroups(&sysuserid,outds=users)
@@ -11846,7 +12035,7 @@ run;
%end; %end;
/* prepare url */ /* prepare url */
%if &grant_type=authorization_code %then %do; %if %index(%superq(grant_type),authorization_code) %then %do;
data _null_; data _null_;
if symexist('_baseurl') then do; if symexist('_baseurl') then do;
url=symget('_baseurl'); url=symget('_baseurl');
@@ -11865,7 +12054,7 @@ run;
%put CLIENT_SECRET=&client_secret; %put CLIENT_SECRET=&client_secret;
%put GRANT_TYPE=&grant_type; %put GRANT_TYPE=&grant_type;
%put; %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 */ /* 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: The developer must also register below and select 'openid' to get the grant code:;
%put NOTE- ; %put NOTE- ;
@@ -11932,6 +12121,7 @@ libname &libref clear;
@param pass= If grant_type=password then provide the password here @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 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 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 @version VIYA V.03.04
@author Allan Bowe @author Allan Bowe
@@ -11956,6 +12146,7 @@ libname &libref clear;
,pass= ,pass=
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,refresh_token_var=REFRESH_TOKEN ,refresh_token_var=REFRESH_TOKEN
,base_uri=#NOTSET#
); );
%global &access_token_var &refresh_token_var; %global &access_token_var &refresh_token_var;
@@ -12002,8 +12193,7 @@ run;
/** /**
* Request access token * Request access token
*/ */
%local base_uri; /* location of rest apis */ %if &base_uri=#NOTSET# %then %let base_uri=%mf_getplatform(VIYARESTAPI);
%let base_uri=%mf_getplatform(VIYARESTAPI);
%let fref2=%mf_getuniquefileref(); %let fref2=%mf_getuniquefileref();
proc http method='POST' in=&grantstring out=&fref2 proc http method='POST' in=&grantstring out=&fref2

View File

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

View File

@@ -23,13 +23,23 @@
**/ **/
%macro mf_trimstr(basestr,trimstr); %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)); %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) %let trimval=%qsubstr(%superq(basestr)
,%length(%superq(basestr))-&trimlen+1 ,%length(%superq(basestr))-&trimlen+1
,&trimlen); ,&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) %qsubstr(%superq(basestr),1,%length(%superq(basestr))-&trimlen)
%end; %end;
%else %do; %else %do;

View File

@@ -6,6 +6,12 @@
results back to the client in an STP Web App context, or completely stop results back to the client in an STP Web App context, or completely stop
in the case of a batch run. 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 mac= to contain the name of the calling macro
@param msg= message to be returned @param msg= message to be returned
@param iftrue= supply a condition under which the macro should be executed. @param iftrue= supply a condition under which the macro should be executed.
@@ -65,8 +71,15 @@
%end; %end;
%if %symexist(SYS_JES_JOB_URI) %then %do; %if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */ /* setup webout */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"; 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; %end;
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */

144
base/mp_csv2ds.sas Normal file
View File

@@ -0,0 +1,144 @@
/**
@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 (lib.ds format)
@param view= Set to YES or NO to determine whether the output should be
a view or not. Default is NO (not a view).
@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
<h4> Dependencies </h4>
@li mp_abort.sas
@li mf_existds.sas
**/
%macro mp_csv2ds(inref=0,outds=0,baseds=0,view=NO);
%mp_abort(iftrue=( &inref=0 )
,mac=&sysmacroname
,msg=%str(the INREF variable must be provided)
)
%mp_abort(iftrue=( %superq(outds)=0 )
,mac=&sysmacroname
,msg=%str(the OUTDS variable must be provided)
)
%mp_abort(iftrue=( &baseds=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS variable must be provided)
)
%mp_abort(iftrue=( &baseds=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS variable must be provided)
)
%mp_abort(iftrue=( %mf_existds(&baseds)=0 )
,mac=&sysmacroname
,msg=%str(the BASEDS dataset (&baseds) needs to be assigned, and to exist)
)
/* count rows */
%local hasheader; %let hasheader=0;
data _null_;
if _N_ > 1 then do;
call symputx('hasheader',1,'l');
stop;
end;
infile &inref;
input;
run;
%mp_abort(iftrue=( &hasheader=0 )
,mac=&sysmacroname
,msg=%str(No header row in &inref)
)
/* 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;
else informat=cats(informat,'.');
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
%if %upcase(&view)=YES %then %do;
/view=&outds
%end;
;
infile &inref dsd firstobs=2;
input &instat;
%if %length(&dropvars)>0 %then %do;
drop &dropvars;
%end;
run;
%mend;

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
@brief Searches all data in a library @brief Searches all data in a library
@details @details
Scans an entire library and creates a copy of any table 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. matching records are written out.
If both a string and numval are provided, the string If both a string and numval are provided, the string
will take precedence. will take precedence.
@@ -44,9 +44,13 @@
,filter_text=%str(1=1) ,filter_text=%str(1=1)
)/*/STORE SOURCE*/; )/*/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.); %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; %if &string = %then %let type=N;
%else %let type=C; %else %let type=C;
@@ -78,6 +82,7 @@ proc sql
%put NO COLUMNS IN &lib..&table! This will be skipped.; %put NO COLUMNS IN &lib..&table! This will be skipped.;
%end; %end;
%else %do; %else %do;
%let check_tm=%sysfunc(datetime());
/* build sql statement */ /* build sql statement */
create table mpsearch.&table as select * from &lib..&table create table mpsearch.&table as select * from &lib..&table
where %unquote(&filter_text) and where %unquote(&filter_text) and
@@ -88,14 +93,19 @@ proc sql
%let coltype=%mf_getvartype(&lib..&table,&col); %let coltype=%mf_getvartype(&lib..&table,&col);
%if &type=C and &coltype=C %then %do; %if &type=C and &coltype=C %then %do;
/* if a char column, see if it contains the string */ /* if a char column, see if it contains the string */
or (&col ? "&string") or ("&col"n ? "&string")
%end; %end;
%else %if &type=N and &coltype=N %then %do; %else %if &type=N and &coltype=N %then %do;
/* if numeric match exactly */ /* if numeric match exactly */
or (&col = &numval) or ("&col"n = &numval)
%end; %end;
%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; %if %mf_nobs(mpsearch.&table)=0 %then %do;
drop table mpsearch.&table; drop table mpsearch.&table;
%end; %end;

View File

@@ -1,5 +1,5 @@
/** /**
@file mp_streamfile.sas @file
@brief Streams a file to _webout according to content type @brief Streams a file to _webout according to content type
@details Will set headers using appropriate functions (SAS 9 vs Viya) and send @details Will set headers using appropriate functions (SAS 9 vs Viya) and send
content as a binary stream. content as a binary stream.
@@ -17,6 +17,7 @@
@param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT) @param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT)
@param inloc= /path/to/file.ext to be sent @param inloc= /path/to/file.ext to be sent
@param inref= fileref of file to be sent (if provided, overrides `inloc`)
@param outname= the name of the file, as downloaded by the browser @param outname= the name of the file, as downloaded by the browser
@author Allan Bowe @author Allan Bowe
@@ -27,6 +28,7 @@
%macro mp_streamfile( %macro mp_streamfile(
contenttype=TEXT contenttype=TEXT
,inloc= ,inloc=
,inref=0
,outname= ,outname=
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
@@ -110,6 +112,11 @@
%return; %return;
%end; %end;
%if &inref ne 0 %then %do;
%mp_binarycopy(inref=&inref,outref=_webout)
%end;
%else %do;
%mp_binarycopy(inloc="&inloc",outref=_webout) %mp_binarycopy(inloc="&inloc",outref=_webout)
%end;
%mend; %mend;

View File

@@ -16,7 +16,7 @@
<tab type="classmembers" visible="no" title="" intro=""/> <tab type="classmembers" visible="no" title="" intro=""/>
</tab> </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=""/> <tab type="examples" visible="yes" title="" intro=""/>
</navindex> </navindex>

View File

@@ -36,5 +36,9 @@ echo 'core.sasjs.io' > CNAME
git add * git add *
git commit -m "build.sh build on $(date +%F:%H:%M:%S)" git commit -m "build.sh build on $(date +%F:%H:%M:%S)"
git push 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" echo "check it out: https://sasjs.github.io/core.github.io/files.html"

View File

@@ -124,6 +124,7 @@ data _null_;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "WARNING: missing value for " entity=; otherwise putlog "WARNING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));

View File

@@ -123,6 +123,7 @@ data _null_;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "%str(WARN)ING: missing value for " entity=; otherwise putlog "%str(WARN)ING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));

View File

@@ -99,6 +99,7 @@ run;
when ('&#x0a;') rec='0A'x; when ('&#x0a;') rec='0A'x;
when ('&#x0d;') rec='0D'x; when ('&#x0d;') rec='0D'x;
when ('&#36;' ) rec='$' ; when ('&#36;' ) rec='$' ;
when ('&#x09;') rec='09'x;
otherwise putlog "WARNING: missing value for " entity=; otherwise putlog "WARNING: missing value for " entity=;
end; end;
rc =fput(fileid, substr(rec,1,1)); rc =fput(fileid, substr(rec,1,1));

View File

@@ -98,7 +98,7 @@ run;
libname &libref1 JSON fileref=&fname1; libname &libref1 JSON fileref=&fname1;
data _null_; data _null_;
set &libref1..links; 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; run;
/* get the children */ /* get the children */
@@ -128,7 +128,7 @@ run;
%put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ; %put NOTE:;%put NOTE- &sysmacroname: &path/&name NOT FOUND;%put NOTE- ;
%return; %return;
%end; %end;
proc http method="DELETE" url="&uri" &oauth_bearer; proc http method="DELETE" url="&base_uri&uri" &oauth_bearer;
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
"Authorization"="Bearer &&&access_token_var" "Authorization"="Bearer &&&access_token_var"

View File

@@ -88,9 +88,9 @@ libname &libref1 JSON fileref=&fname1;
data _null_; data _null_;
set &libref1..links; set &libref1..links;
if rel='deleteRecursively' then 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 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; run;
/* before we can delete the folder, we need to delete the children */ /* before we can delete the folder, we need to delete the children */
@@ -111,7 +111,7 @@ data _null_;
set &libref1a..items_links; set &libref1a..items_links;
if href=:'/folders/folders' then return; if href=:'/folders/folders' then return;
if rel='deleteResource' then 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" ' !!'; headers "Authorization"="Bearer &&&access_token_var" '
!!' "Accept"="*/*";run; /**/'); !!' "Accept"="*/*";run; /**/');
run; run;

View File

@@ -1,6 +1,6 @@
/** /**
@file mv_getgroups.sas @file mv_getclients.sas
@brief Creates a dataset with a list of viya groups @brief Get a list of Viya Clients
@details First, be sure you have an access token (which requires an app token). @details First, be sure you have an access token (which requires an app token).
Using the macros here: Using the macros here:
@@ -20,7 +20,7 @@
Now we can run the macro! Now we can run the macro!
%mv_getgroups() %mv_getclients()
@param access_token_var= The global macro variable to contain the access token @param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted). @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"="/" %then %do;
/* if root just list root folders */ /* if root just list root folders */
proc http method='GET' out=&fname1 &oauth_bearer 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; %if &grant_type=authorization_code %then %do;
headers "Authorization"="Bearer &&&access_token_var"; headers "Authorization"="Bearer &&&access_token_var";
%end; %end;
@@ -87,7 +87,7 @@ options noquotelenmax;
/* now get the followon link to list members */ /* now get the followon link to list members */
data _null_; data _null_;
set &libref1..links; 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; run;
%local fname2 libref2; %local fname2 libref2;
%let fname2=%mf_getuniquefileref(); %let fname2=%mf_getuniquefileref();

View File

@@ -1,24 +1,15 @@
/** /**
@file mv_getusergroups.sas @file mv_getusergroups.sas
@brief Creates a dataset with a list of groups for a particular user @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 filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas"; "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc; %inc mc;
An administrator needs to set you up with an access code: Then run the macro!
%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!
%mv_getusergroups(&sysuserid,outds=users) %mv_getusergroups(&sysuserid,outds=users)

View File

@@ -187,7 +187,7 @@ run;
%end; %end;
/* prepare url */ /* prepare url */
%if &grant_type=authorization_code %then %do; %if %index(%superq(grant_type),authorization_code) %then %do;
data _null_; data _null_;
if symexist('_baseurl') then do; if symexist('_baseurl') then do;
url=symget('_baseurl'); url=symget('_baseurl');
@@ -206,7 +206,7 @@ run;
%put CLIENT_SECRET=&client_secret; %put CLIENT_SECRET=&client_secret;
%put GRANT_TYPE=&grant_type; %put GRANT_TYPE=&grant_type;
%put; %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 */ /* 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: The developer must also register below and select 'openid' to get the grant code:;
%put NOTE- ; %put NOTE- ;

View File

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