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

Compare commits

...

6 Commits

12 changed files with 192 additions and 52 deletions

5
.gitignore vendored
View File

@@ -6,4 +6,7 @@ sasjsbuild/
**\ **
# ignore the mc_* files - containing macros for individual libraries
mc_*
mc_*
# ignore .env files as they can contain sasjs access tokens
*.env*

View File

@@ -5,4 +5,4 @@ image:
file: .gitpod.dockerfile
vscode:
extensions:
- sasjs.sasjs-for-vscode@1.7.2:R6y1nzpFh2P99BZg5FgH5g==
- sasjs.sasjs-for-vscode

View File

@@ -2,6 +2,9 @@
"noTrailingSpaces": true,
"noEncodedPasswords": true,
"hasDoxygenHeader": true,
"hasMacroNameInMend": false,
"hasMacroParentheses": true,
"noNestedMacros": false,
"noSpacesInFileNames": true,
"maxLineLength": 135,
"lowerCaseFileNames": true,

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"recommendations": [
"sasjs.sasjs-for-vscode"
]
}

130
all.sas
View File

@@ -3919,8 +3919,11 @@ create table &outds (rename=(
@details PROC JSON is faster but will produce errs like the ones below if
special chars are encountered.
>An object or array close is not valid at this point in the JSON text.
>Date value out of range
> ERROR: Some code points did not transcode.
> An object or array close is not valid at this point in the JSON text.
> Date value out of range
If this happens, try running with ENGINE=DATASTEP.
@@ -3929,7 +3932,9 @@ create table &outds (rename=(
filename tmp temp;
data class; set sashelp.class;run;
%mp_jsonout(OPEN,jref=tmp)
%mp_jsonout(OBJ,class,jref=tmp)
%mp_jsonout(CLOSE,jref=tmp)
data _null_;
infile tmp;
@@ -3942,18 +3947,18 @@ create table &outds (rename=(
For more information see https://sasjs.io
@param action Valid values:
* OPEN - opens the JSON
* OBJ - sends a table with each row as an object
* ARR - sends a table with each row in an array
* CLOSE - closes the JSON
@li OPEN - opens the JSON
@li OBJ - sends a table with each row as an object
@li ARR - sends a table with each row in an array
@li CLOSE - closes the JSON
@param ds the dataset to send. Must be a work table.
@param jref= the fileref to which to send the JSON
@param dslabel= the name to give the table in the exported JSON
@param fmt= Whether to keep or strip formats from the table
@param engine= Which engine to use to send the JSON, options are:
* PROCJSON (default)
* DATASTEP
@param engine= Which engine to use to send the JSON, valid options are:
@li PROCJSON (default)
@li DATASTEP (more reliable when data has non standard characters)
@param dbg= DEPRECATED - was used to conditionally add PRETTY to
proc json but this can cause line truncation in large files.
@@ -4075,11 +4080,12 @@ create table &outds (rename=(
%end;
%else %if &action=CLOSE %then %do;
data _null_;file &jref encoding='utf-8';
data _null_;file &jref encoding='utf-8' mod;
put "}";
run;
%end;
%mend;/**
%mend;
/**
@file
@brief Convert all library members to CARDS files
@details Gets list of members then calls the <code>%mp_ds2cards()</code> macro.
@@ -5368,6 +5374,60 @@ alter table &libds modify &var char(&len);
%mend;
/**
@file
@brief Validates a filter clause
@details Validates a filter to avoid SQL injection. Works by removing string
literals, then ensuring that none of the following characters remain: &,%,;
%mp_setkeyvalue(someindex,22,type=N)
%mp_setkeyvalue(somenewindex,somevalue)
<h4> SAS Macros </h4>
@li mf_existds.sas
@param key Provide a key on which to perform the lookup
@param value Provide a value
@param type= either C or N will populate valc and valn respectively. C is
default.
@param libds= define the target table to hold the parameters
@version 9.2
@author Allan Bowe
@source https://github.com/sasjs/core
**/
%macro mp_setkeyvalue(key,value,type=C,libds=work.mp_setkeyvalue
)/*/STORE SOURCE*/;
%if not (%mf_existds(&libds)) %then %do;
data &libds (index=(key/unique));
length key $64 valc $2048 valn 8 type $1;
call missing(of _all_);
stop;
run;
%end;
proc sql;
delete from &libds
where key=symget('key');
insert into &libds
set key=symget('key')
%if &type=C %then %do;
,valc=symget('value')
,type='C'
%end;
%else %do;
,valn=symgetn('value')
,type='N'
%end;
;
quit;
%mend;/**
@file
@brief Creates a zip file
@details For DIRECTORY usage, will ignore subfolders. For DATASET usage,
@@ -7301,8 +7361,6 @@ run;
*/
%mm_updatestpsourcecode(stp=&tree/&stpname
,stpcode="&directory/&filename"
,frefin=&frefin.
,frefout=&frefout.
,mdebug=&mdebug
,minify=&minify)
@@ -7510,7 +7568,7 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=CLOSE %then %do; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' data _null_;file &jref encoding=''utf-8'' mod; ';
put ' put "}"; ';
put ' run; ';
put '%end; ';
@@ -7591,14 +7649,14 @@ data _null_;
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put ",""WORK"":{"; ';
put ' %do i=1 %to &wtcnt; ';
put ' %let wt=&&wt&i; ';
put ' proc contents noprint data=&wt ';
put ' out=_data_ (keep=name type length format:); ';
put ' run;%let tempds=%scan(&syslast,2,.); ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' dsid=open("WORK.&wt",''is''); ';
put ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); ';
@@ -7609,10 +7667,10 @@ data _null_;
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' %end; ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' run; ';
put ' %end; ';
@@ -11060,14 +11118,14 @@ run;
i+1;
call symputx('wt'!!left(i),name,'l');
call symputx('wtcnt',i,'l');
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put ",""WORK"":{";
%do i=1 %to &wtcnt;
%let wt=&&wt&i;
proc contents noprint data=&wt
out=_data_ (keep=name type length format:);
run;%let tempds=%scan(&syslast,2,.);
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
dsid=open("WORK.&wt",'is');
nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS');
@@ -11078,10 +11136,10 @@ run;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put "}";
%end;
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put "}";
run;
%end;
@@ -11748,9 +11806,10 @@ run;
needs to be attached to the beginning of the service
@param code= Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param replace= select NO to avoid replacing any existing service in that location
@param grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param replace= select NO to avoid replacing any existing service in that
location
@param adapter= the macro uses the sasjs adapter by default. To use another
adapter, add a (different) fileref here.
@param contextname= Choose a specific context on which to run the Job. Leave
@@ -11847,7 +11906,8 @@ libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
if rel='members' then
call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
else if rel='self' then call symputx('parentFolderUri',href,'l');
run;
data _null_;
@@ -12037,7 +12097,7 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=CLOSE %then %do; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' data _null_;file &jref encoding=''utf-8'' mod; ';
put ' put "}"; ';
put ' run; ';
put '%end; ';
@@ -12169,7 +12229,7 @@ data _null_;
put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=PROCJSON,dbg=%str(&_debug) ';
put ' ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -12294,6 +12354,14 @@ run;
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'\');rc =fwrite(fileid);
end;
else if rec='01'x then do; /* Unprintable */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);
@@ -15376,7 +15444,7 @@ libname &libref clear;
filename &fref1 clear;
%mend;/**
@file mv_webout.sas
@file
@brief Send data to/from the SAS Viya Job Execution Service
@details This macro should be added to the start of each Job Execution
Service, **immediately** followed by a call to:
@@ -15388,7 +15456,7 @@ filename &fref1 clear;
following syntax:
data some datasets; * make some data ;
retain some columns;
retain some columns;
run;
%mv_webout(OPEN)
@@ -15539,7 +15607,7 @@ filename &fref1 clear;
%end;
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
,jref=&fref,engine=PROCJSON,dbg=%str(&_debug)
,jref=&fref,engine=DATASTEP,dbg=%str(&_debug)
)
%end;
%else %if &action=CLOSE %then %do;

View File

@@ -376,8 +376,6 @@ run;
*/
%mm_updatestpsourcecode(stp=&tree/&stpname
,stpcode="&directory/&filename"
,frefin=&frefin.
,frefout=&frefout.
,mdebug=&mdebug
,minify=&minify)

View File

@@ -196,7 +196,7 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=CLOSE %then %do; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' data _null_;file &jref encoding=''utf-8'' mod; ';
put ' put "}"; ';
put ' run; ';
put '%end; ';
@@ -277,14 +277,14 @@ data _null_;
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put ",""WORK"":{"; ';
put ' %do i=1 %to &wtcnt; ';
put ' %let wt=&&wt&i; ';
put ' proc contents noprint data=&wt ';
put ' out=_data_ (keep=name type length format:); ';
put ' run;%let tempds=%scan(&syslast,2,.); ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' dsid=open("WORK.&wt",''is''); ';
put ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); ';
@@ -295,10 +295,10 @@ data _null_;
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' %end; ';
put ' data _null_; file &fref encoding=''utf-8''; ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' run; ';
put ' %end; ';

View File

@@ -108,14 +108,14 @@
i+1;
call symputx('wt'!!left(i),name,'l');
call symputx('wtcnt',i,'l');
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put ",""WORK"":{";
%do i=1 %to &wtcnt;
%let wt=&&wt&i;
proc contents noprint data=&wt
out=_data_ (keep=name type length format:);
run;%let tempds=%scan(&syslast,2,.);
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
dsid=open("WORK.&wt",'is');
nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS');
@@ -126,10 +126,10 @@
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put "}";
%end;
data _null_; file &fref encoding='utf-8';
data _null_; file &fref mod encoding='utf-8';
put "}";
run;
%end;

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
"macroFolders": ["base", "meta", "metax", "viya", "lua"],
"docConfig":{
"docConfig": {
"displayMacroCore": false,
"enableLineage": false,
"doxyContent": {
@@ -9,5 +9,26 @@
"logo": "Macro_core_website_1.png",
"readMe": "../../README.md"
}
}
},
"serviceConfig": {
"initProgram": "tests/testinit.sas"
},
"defaultTarget": "viya",
"targets": [
{
"name": "viya",
"serverUrl": "https://sas.analytium.co.uk",
"serverType": "SASVIYA",
"appLoc": "/Public/temp/macrocore",
"serviceConfig": {
"serviceFolders": ["tests/viya"],
"macroVars": {
"mcTestAppLoc": "/Public/temp/macrocore"
}
},
"deployConfig": {
"deployServicePack": true
}
}
]
}

8
tests/testinit.sas Normal file
View File

@@ -0,0 +1,8 @@
/**
@file
@brief init file for tests
**/
/* location in metadata or SAS Drive for temporary files */
%let mcTestAppLoc=/Public/temp/test;

View File

@@ -0,0 +1,24 @@
/**
@file
@brief Testing mv_createwebservice macro
<h4> SAS Macros </h4>
@li mv_createwebservice.sas
**/
/**
* Test Case 1
* Send special char in a service
*/
filename testref temp;
data _null_;
file testref;
put '01'x;
run;
%mv_createwebservice(
path=&mcTestAppLoc/tests/macros,
code=testref,
name=mv_createwebservice
)

View File

@@ -46,9 +46,10 @@
needs to be attached to the beginning of the service
@param code= Fileref(s) of the actual code to be added
@param access_token_var= The global macro variable to contain the access token
@param grant_type= valid values are "password" or "authorization_code" (unquoted).
The default is authorization_code.
@param replace= select NO to avoid replacing any existing service in that location
@param grant_type= valid values are "password" or "authorization_code"
(unquoted). The default is authorization_code.
@param replace= select NO to avoid replacing any existing service in that
location
@param adapter= the macro uses the sasjs adapter by default. To use another
adapter, add a (different) fileref here.
@param contextname= Choose a specific context on which to run the Job. Leave
@@ -145,7 +146,8 @@ libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..links;
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
if rel='members' then
call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
else if rel='self' then call symputx('parentFolderUri',href,'l');
run;
data _null_;
@@ -335,7 +337,7 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=CLOSE %then %do; ';
put ' data _null_;file &jref encoding=''utf-8''; ';
put ' data _null_;file &jref encoding=''utf-8'' mod; ';
put ' put "}"; ';
put ' run; ';
put '%end; ';
@@ -467,7 +469,7 @@ data _null_;
put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=PROCJSON,dbg=%str(&_debug) ';
put ' ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -592,6 +594,14 @@ run;
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'\');rc =fwrite(fileid);
end;
else if rec='01'x then do; /* Unprintable */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);