1
0
mirror of https://github.com/sasjs/core.git synced 2026-06-09 12:10:22 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions 2b74caede4 chore: updating all.sas 2026-03-19 00:52:45 +00:00
34 changed files with 181 additions and 2210 deletions
-25
View File
@@ -54,7 +54,6 @@ jobs:
echo "REFRESH_TOKEN=${{secrets.SAS9_4GL_IO_REFRESH_TOKEN}}" >> .env.server echo "REFRESH_TOKEN=${{secrets.SAS9_4GL_IO_REFRESH_TOKEN}}" >> .env.server
- name: Semantic Release - name: Semantic Release
id: makerelease
uses: cycjimmy/semantic-release-action@v6 uses: cycjimmy/semantic-release-action@v6
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -65,27 +64,3 @@ jobs:
npx @sasjs/cli compile job -s sasjs/utils/create_sas_package.sas -o sasjsbuild -t server npx @sasjs/cli compile job -s sasjs/utils/create_sas_package.sas -o sasjsbuild -t server
# need long duration token per https://github.com/sasjs/server/issues/307 # need long duration token per https://github.com/sasjs/server/issues/307
# npx @sasjs/cli run sasjsbuild/jobs/utils/create_sas_package.sas -t server # npx @sasjs/cli run sasjsbuild/jobs/utils/create_sas_package.sas -t server
- name: Update Docs Site
if: steps.makerelease.outputs.new_release_published == 'true'
run: |
sudo apt-get update
sudo apt-get install -y doxygen
npx @sasjs/cli doc -t docsonly
git clone https://x-access-token:${{ secrets.CORESASJSIO_PAT }}@github.com/sasjs/core.github.io.git
cd core.github.io
rm -rf *.html
rm -rf *.js
rm -rf *.png
rm -rf *.dot
rm -rf *.css
rm -rf *.svg
rm -rf search
cp -R ../sasjsbuild/docs/* .
ls
git config user.name sasjs
echo 'core.sasjs.io' > CNAME
git add .
git commit -m "core pipeline build on $(date +%F:%H:%M:%S)"
git push
echo "check it out: https://sasjs.github.io/core.github.io/files.html"
-1
View File
@@ -26,7 +26,6 @@ jobs:
git config user.email github-actions@github.com git config user.email github-actions@github.com
python3 build.py python3 build.py
git add all.sas git add all.sas
git add viya/mv_createwebservice.sas
git commit -m "chore: updating all.sas" --allow-empty git commit -m "chore: updating all.sas" --allow-empty
git push git push
-1
View File
@@ -14,4 +14,3 @@ mc_*
~ ~
.claude
+3 -1
View File
@@ -5,6 +5,8 @@
![npm](https://img.shields.io/npm/dt/@sasjs/core) ![npm](https://img.shields.io/npm/dt/@sasjs/core)
![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core) ![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core)
[![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues-raw/sasjs/core)](https://github.com/sasjs/core/issues)
![total lines](https://tokei.rs/b1/github/sasjs/core)
Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of [Application Development](https://sasapps.io) on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/.github/CONTRIBUTING.md) are welcome. Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of [Application Development](https://sasapps.io) on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/.github/CONTRIBUTING.md) are welcome.
@@ -199,7 +201,7 @@ When contributing to this library, it is therefore important to ensure that all
- All dataset references must be 2 level (eg `work.blah`, not `blah`). This is to avoid contention when options [DATASTMTCHK](https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000279064.htm)=ALLKEYWORDS is in effect, or the [USER](https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/n18m1vkqmeo4esn1moikt23zhp8s.htm) library is active. - All dataset references must be 2 level (eg `work.blah`, not `blah`). This is to avoid contention when options [DATASTMTCHK](https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000279064.htm)=ALLKEYWORDS is in effect, or the [USER](https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/n18m1vkqmeo4esn1moikt23zhp8s.htm) library is active.
- Avoid naming collisions! All macro variables should be local scope. Use system generated work tables where possible - eg `data ; set sashelp.class; run; data &output; set &syslast; run;` - Avoid naming collisions! All macro variables should be local scope. Use system generated work tables where possible - eg `data ; set sashelp.class; run; data &output; set &syslast; run;`
- Where global macro variables are absolutely necessary, they should make use of `&sasjs_prefix` - see mp_init.sas - Where global macro variables are absolutely necessary, they should make use of `&sasjs_prefix` - see mp_init.sas
- The use of `quit;` for `proc sql` is essential, to avoid `WARNING: You cannot disconnect or terminate session XXXX until the procedure completes.` when terminating CAS sessions in Viya. - The use of `quit;` for `proc sql` is optional unless you are looking to benefit from the timing statistics.
- Use [sasjs lint](https://github.com/sasjs/lint)! - Use [sasjs lint](https://github.com/sasjs/lint)!
## General Notes ## General Notes
+68 -719
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -52,6 +52,5 @@
run; run;
proc sql; proc sql;
drop table &ds; drop table &ds;
quit;
%mend mp_assert; %mend mp_assert;
+1 -2
View File
@@ -92,7 +92,6 @@
from dictionary.macros from dictionary.macros
where scope="&scope" and upcase(name) not in (%mf_getquotedstr(&ilist)) where scope="&scope" and upcase(name) not in (%mf_getquotedstr(&ilist))
order by name,offset; order by name,offset;
quit;
%end; %end;
%else %if &action=COMPARE %then %do; %else %if &action=COMPARE %then %do;
@@ -130,6 +129,7 @@
%let test_comments=%str(Mod:(&mod) Add:(&add) Del:(&del)); %let test_comments=%str(Mod:(&mod) Add:(&add) Del:(&del));
%end; %end;
data ; data ;
length test_description $256 test_result $4 test_comments $256; length test_description $256 test_result $4 test_comments $256;
test_description=symget('desc'); test_description=symget('desc');
@@ -142,7 +142,6 @@
run; run;
proc sql; proc sql;
drop table &ds; drop table &ds;
quit;
%end; %end;
%mend mp_assertscope; %mend mp_assertscope;
+1 -2
View File
@@ -41,9 +41,8 @@
&prefix._INIT_NUM /* initialisation time as numeric */ &prefix._INIT_NUM /* initialisation time as numeric */
&prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */ &prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */
&prefix.WORK /* avoid typing %sysfunc(pathname(work)) every time */ &prefix.WORK /* avoid typing %sysfunc(pathname(work)) every time */
&prefix.PROCESSMODE
&prefix._STPSRV_HEADER_LOC
; ;
%let sasjs_prefix=&prefix; %let sasjs_prefix=&prefix;
data _null_; data _null_;
+1 -15
View File
@@ -1,6 +1,6 @@
/** /**
@file @file
@brief Used to validate values in a data step @brief Used to validate variables in a dataset
@details Useful when sanitising inputs, to ensure that they arrive with a @details Useful when sanitising inputs, to ensure that they arrive with a
certain pattern. certain pattern.
Usage: Usage:
@@ -27,7 +27,6 @@
@param [in] incol The column to be validated @param [in] incol The column to be validated
@param [in] rule The rule to apply. Current rules: @param [in] rule The rule to apply. Current rules:
@li ISINT - checks if the variable is an integer @li ISINT - checks if the variable is an integer
@li ISLIB - checks if the value is a valid libref (NOT whether it exists)
@li ISNUM - checks if the variable is numeric @li ISNUM - checks if the variable is numeric
@li LIBDS - matches LIBREF.DATASET format @li LIBDS - matches LIBREF.DATASET format
@li FORMAT - checks if the provided format is syntactically valid @li FORMAT - checks if the provided format is syntactically valid
@@ -66,19 +65,6 @@
else &outcol=1; else &outcol=1;
drop &tempcol; drop &tempcol;
%end; %end;
%else %if &rule=ISLIB %then %do;
if _n_=1 then do;
retain &tempcol;
&tempcol=prxparse('/^[_a-z]\w{0,7}$/i');
if missing(&tempcol) then do;
putlog 'ERR' +(-1) "OR: Invalid expression for ISLIB";
stop;
end;
drop &tempcol;
end;
if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
else &outcol=0;
%end;
%else %if &rule=LIBDS %then %do; %else %if &rule=LIBDS %then %do;
/* match libref.dataset */ /* match libref.dataset */
if _n_=1 then do; if _n_=1 then do;
+1 -4
View File
@@ -31,8 +31,5 @@
"test": "npx @sasjs/cli test -t server", "test": "npx @sasjs/cli test -t server",
"lint": "npx @sasjs/cli lint", "lint": "npx @sasjs/cli lint",
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true" "prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
}, }
"maintainers": [
"https://sasapps.io"
]
} }
+4 -5
View File
@@ -21,7 +21,6 @@
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css" /> <link href="$relpath^tabs.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="$relpath^jquery.js"></script> <script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script> <script type="text/javascript" src="$relpath^dynsections.js"></script>
<script type="text/javascript" src="$relpath^cookie.js"></script>
$treeview $search $mathjax $treeview $search $mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
@@ -40,10 +39,6 @@
g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s); g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s);
})(); })();
</script> </script>
<noscript>
<p><img referrerpolicy="no-referrer-when-downgrade" src="https://analytics.4gl.io/matomo.php?idsite=6&amp;rec=1"
style="border:0;" alt="" /></p>
</noscript>
<!-- End Matomo Code --> <!-- End Matomo Code -->
</head> </head>
@@ -85,3 +80,7 @@
</div> </div>
<!--END TITLEAREA--> <!--END TITLEAREA-->
<!-- end header part --> <!-- end header part -->
</div>
</body>
</html>
+4 -1
View File
@@ -25,7 +25,10 @@
}, },
"testConfig": { "testConfig": {
"initProgram": "tests/testinit.sas", "initProgram": "tests/testinit.sas",
"termProgram": "tests/testterm.sas" "termProgram": "tests/testterm.sas",
"macroVars": {
"mcTestAppLoc": "/Public/temp/macrocore"
}
}, },
"defaultTarget": "server", "defaultTarget": "server",
"targets": [ "targets": [
-26
View File
@@ -130,29 +130,3 @@ run;
test=EQUALS 6, test=EQUALS 6,
outds=work.test_results outds=work.test_results
) )
/**
* Test 5 - ISLIB
*/
data test5;
infile datalines4 dsd;
input;
inf=_infile_;
%mp_validatecol(inf,ISLIB,islib)
if islib=1;
datalines4;
some
!lib
%abort
definite
2fail
nineletrs
.failalso
_valid
;;;;
run;
%mp_assertdsobs(work.test5,
desc=Testing ISLIB,
test=EQUALS 3,
outds=work.test_results
)
+1 -4
View File
@@ -10,9 +10,7 @@
**/ **/
/* location in metadata or SAS Drive for temporary files */ /* location in metadata or SAS Drive for temporary files */
%let mcTestAppLoc=/Users/&sysuserid/testresults/sasjs_core/%mf_uid(); %let mcTestAppLoc=/Public/testresults/sasjs_core/%mf_uid();
%let mcTestContext=SAS Job Execution compute context;
/* set defaults */ /* set defaults */
%mp_init() %mp_init()
@@ -25,7 +23,6 @@ options lrecl=80;
%macro loglevel(); %macro loglevel();
%if "&_debug"="2477" or "&_debug"="fields,log,trace" or "&_debug"="131" %if "&_debug"="2477" or "&_debug"="fields,log,trace" or "&_debug"="131"
or "&_debug"="128"
%then %do; %then %do;
%put debug mode activated; %put debug mode activated;
options mprint mprintnest; options mprint mprintnest;
-74
View File
@@ -1,74 +0,0 @@
/**
@file
@brief Testing mfv_existsashdat macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existsashdat.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
options mprint;
/* ------------------------------------------------------------------------ */
/* Setup: start a CAS session and stage a sashdat file in the Public caslib */
/* ------------------------------------------------------------------------ */
cas mysess;
caslib _all_ assign;
%let testcaslib = Public; /* change this if Public isn't available */
proc cas;
table.caslibInfo result=r / ;
found = 0;
do row over r.CASLibInfo;
if upcase(row.Name) = upcase("&testcaslib") then found = 1;
end;
if found = 0 then do;
print "ERROR: caslib &testcaslib not available";
exit;
end;
quit;
%put NOTE: Using testcaslib=&testcaslib;
%let tab1=T%mf_uid();
proc casutil;
load data=sashelp.baseball outcaslib="&testcaslib" casout="&tab1" replace;
save casdata="&tab1" incaslib="&testcaslib"
casout="&tab1..sashdat" outcaslib="&testcaslib" replace;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
quit;
/* ------------------------------------------------------------------------ */
%put TEST 1 - returns 1 when the sashdat file exists in the caslib;
/* ------------------------------------------------------------------------ */
%mp_assert(
iftrue=(%mfv_existsashdat(&testcaslib..&tab1)=1),
desc=Test 1 - Check returns 1 for a sashdat that exists
)
/* ------------------------------------------------------------------------ */
%put TEST 2 - returns 0 when the file does not exist in the caslib;
/* ------------------------------------------------------------------------ */
%mp_assertscope(SNAPSHOT)
%mp_assert(
iftrue=(%mfv_existsashdat(&testcaslib..DOESNOTEXIST_%mf_uid())=0),
desc=Check returns 0 for a sashdat that does not exist
)
%mp_assertscope(COMPARE,
desc=Check mfv_existsashdat does not leak macro variables into GLOBAL scope
)
/* ------------------------------------------------------------------------ */
/* Teardown */
/* ------------------------------------------------------------------------ */
proc casutil;
deletesource casdata="&tab1..sashdat" incaslib="&testcaslib" quiet;
quit;
cas mysess terminate;
%let syscc=0;
-69
View File
@@ -1,69 +0,0 @@
/**
@file
@brief Testing mfv_getcaslib macro function
<h4> SAS Macros </h4>
@li mfv_getcaslib.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
options mprint;
/* ------------------------------------------------------------------------ */
/* Setup: start a CAS session and assign caslibs */
/* ------------------------------------------------------------------------ */
cas mysess;
caslib _all_ assign;
%let testcaslib=Public;
libname castest cas caslib=&testcaslib;
/* ------------------------------------------------------------------------ */
%put TEST 1 - returns the caslib name for a valid CAS libref;
/* ------------------------------------------------------------------------ */
%mp_assert(
iftrue=(%mfv_getcaslib(castest)=%upcase(&testcaslib)),
desc=Check correct caslib name returned for a valid CAS libref
)
/* ------------------------------------------------------------------------ */
%put TEST 2 - returns empty for a non-CAS libref (WORK);
/* ------------------------------------------------------------------------ */
%mp_assert(
iftrue=(%mfv_getcaslib(WORK)=),
desc=Check empty string returned for a non-CAS libref
)
/* ------------------------------------------------------------------------ */
%put TEST 3 - returns empty for a libref that does not exist;
/* ------------------------------------------------------------------------ */
%mp_assert(
iftrue=(%mfv_getcaslib(DOESNOTEXIST)=),
desc=Check empty string returned for a non-existent libref
)
/* ------------------------------------------------------------------------ */
%put TEST 5 - no scope leakage into global macro variables;
/* ------------------------------------------------------------------------ */
%mp_assertscope(SNAPSHOT)
%let _rc=%mfv_getcaslib(castest);
%mp_assertscope(COMPARE,
desc=Check mfv_getcaslib does not leak macro variables into GLOBAL scope,
ignorelist=_RC
)
/* ------------------------------------------------------------------------ */
/* Teardown */
/* ------------------------------------------------------------------------ */
cas mysess terminate;
-152
View File
@@ -1,152 +0,0 @@
/**
@file
@brief Testing mv_castabload macro
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mv_castabload.sas
**/
options mprint;
/* -------------------------------------------------------------------- */
/* Setup: start a CAS session and stage a source file in the caslib */
/* -------------------------------------------------------------------- */
cas mysess;
caslib _all_ assign;
%let testcaslib=Public;
proc cas;
table.caslibInfo result=r / ;
found=0;
do row over r.CASLibInfo;
if upcase(row.Name)=upcase("&testcaslib") then found=1;
end;
if found=0 then do;
print "ERROR: caslib &testcaslib not available";
exit;
end;
quit;
%put NOTE: Using testcaslib=&testcaslib;
%let tab1=T%mf_uid();
/* Save a sashdat source file then drop the in-memory copy so the first
mv_castabload call has something to load */
proc casutil;
load data=sashelp.baseball
outcaslib="&testcaslib" casout="&tab1" replace;
save casdata="&tab1" incaslib="&testcaslib"
casout="&tab1..sashdat" outcaslib="&testcaslib" replace;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
quit;
libname mylib cas caslib="&testcaslib";
/* -------------------------------------------------------------------- */
%put TEST 1 - load a table that is not in memory;
/* -------------------------------------------------------------------- */
/* Confirm table is absent before the call */
%let _tabexists=0;
proc cas;
table.tableExists result=r /
caslib="&testcaslib" name="&tab1";
if r.exists > 0 then call symputx('_tabexists','1');
quit;
%mp_assert(
iftrue=(&_tabexists=0),
desc=Check table is not in memory before mv_castabload
)
%mv_castabload(lib=mylib, table=&tab1, mdebug=1)
%let _tabexists=0;
proc cas;
table.tableExists result=r /
caslib="&testcaslib" name="&tab1";
if r.exists > 0 then call symputx('_tabexists','1');
quit;
%mp_assert(
iftrue=(&_tabexists=1),
desc=Check table is in memory after mv_castabload
)
/* -------------------------------------------------------------------- */
%put TEST 2 - reload fetches a fresh copy and discards in-memory changes;
/* -------------------------------------------------------------------- */
/* Append a sentinel row to the in-memory table */
data work.extra;
set mylib.&tab1;
name='TESTROW';
output;
stop;
run;
proc casutil;
load data=work.extra casout="&tab1"
outcaslib="&testcaslib" append;
quit;
%let _modified=0;
proc sql noprint;
select count(*) into :_modified
from mylib.&tab1
where name='TESTROW';
quit;
%mp_assert(
iftrue=(&_modified=1),
desc=Check sentinel row is present in memory before reload
)
/* Drop the table and reload - source file does not have the sentinel */
proc casutil;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
quit;
%mp_assertscope(SNAPSHOT)
%mv_castabload(lib=mylib, table=&tab1, mdebug=1)
%mp_assertscope(COMPARE,
desc=Check mv_castabload does not leak macro variables into GLOBAL scope
)
%let _after=0;
proc sql noprint;
select count(*) into :_after
from mylib.&tab1
where name='TESTROW';
quit;
%mp_assert(
iftrue=(&_after=0),
desc=Check sentinel row is absent after reload from source
)
/* -------------------------------------------------------------------- */
/* Teardown */
/* -------------------------------------------------------------------- */
libname mylib clear;
proc casutil;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
deletesource casdata="&tab1..sashdat"
incaslib="&testcaslib" quiet;
quit;
cas mysess terminate;
%let syscc=0;
-158
View File
@@ -1,158 +0,0 @@
/**
@file
@brief Testing mv_castabsave macro
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mv_castabsave.sas
**/
options mprint;
/* -------------------------------------------------------------------- */
/* Setup: start a CAS session and load a table that has a tracked */
/* source file so mv_castabsave can discover it via the REST API */
/* -------------------------------------------------------------------- */
cas mysess;
caslib _all_ assign;
%let testcaslib=Public;
proc cas;
table.caslibInfo result=r / ;
found=0;
do row over r.CASLibInfo;
if upcase(row.Name)=upcase("&testcaslib") then found=1;
end;
if found=0 then do;
print "ERROR: caslib &testcaslib not available";
exit;
end;
quit;
%put NOTE: Using testcaslib=&testcaslib;
%let tab1=T%mf_uid();
/* Load sashelp.class into CAS, save as sashdat, reload from that file
so the table has a tracked source path (needed for REST discovery) */
proc casutil;
load data=sashelp.class
outcaslib="&testcaslib" casout="&tab1" replace;
save casdata="&tab1" incaslib="&testcaslib"
casout="&tab1..sashdat" outcaslib="&testcaslib" replace;
/* Drop any existing global-scope version before promoting */
/* runs twice (with quiet) as first would drop local scope if exists */
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
load casdata="&tab1..sashdat" incaslib="&testcaslib"
casout="&tab1" outcaslib="&testcaslib" promote;
quit;
libname mylib cas caslib="&testcaslib";
/* -------------------------------------------------------------------- */
%put TEST 1 - save in-memory table back to disk + no scope leakage;
/* -------------------------------------------------------------------- */
/* Source file is removed so that the reload proves mv_castabsave
created the file from scratch, not that a prior version existed */
proc casutil;
deletesource casdata="&tab1..sashdat"
incaslib="&testcaslib" quiet;
quit;
/* Insert a sentinel row - it must survive the full save/drop/reload */
data work.appendme;
set mylib.&tab1;
name='TESTROW';
output;
stop;
proc casutil;
load data=work.appendme casout="&tab1" outcaslib="&testcaslib" append;
quit;
%mp_assertscope(SNAPSHOT)
%mv_castabsave(lib=mylib, table=&tab1, mdebug=1)
%mp_assertscope(COMPARE,
desc=Check mv_castabsave does not leak macro variables into GLOBAL scope,
ignorelist=MC0_JADP1LEN MC0_JADP2LEN MC0_JADP3LEN MC0_JADPNUM MC0_JADVLEN
)
proc casutil;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
load casdata="&tab1..sashdat" incaslib="&testcaslib"
casout="&tab1" outcaslib="&testcaslib" promote;
quit;
%let _rowcount=0;
proc sql noprint;
select count(*) into :_rowcount
from mylib.&tab1
where name='TESTROW';
quit;
%mp_assert(
iftrue=(&_rowcount=1),
desc=Check inserted row survives mv_castabsave round-trip to disk
)
/* -------------------------------------------------------------------- */
%put TEST 2 - save overwrites an existing source file;
/* -------------------------------------------------------------------- */
/* Source file already exists from the TEST 1 save - append a new row */
data work.appendme;
set mylib.&tab1;
name='TESTROW2';
output;
stop;
proc casutil;
load data=work.appendme casout="&tab1"
outcaslib="&testcaslib" append;
quit;
%mv_castabsave(lib=mylib, table=&tab1, mdebug=1)
proc casutil;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
load casdata="&tab1..sashdat" incaslib="&testcaslib"
casout="&tab1" outcaslib="&testcaslib" promote;
quit;
%let _rowcount=0;
proc sql noprint;
select count(*) into :_rowcount
from mylib.&tab1
where name='TESTROW2';
quit;
%mp_assert(
iftrue=(&_rowcount=1),
desc=Check inserted row survives save over an existing source file
)
/* -------------------------------------------------------------------- */
/* Teardown */
/* -------------------------------------------------------------------- */
libname mylib clear;
proc casutil;
droptable casdata="&tab1" incaslib="&testcaslib" quiet;
deletesource casdata="&tab1..sashdat"
incaslib="&testcaslib" quiet;
quit;
cas mysess terminate;
%let syscc=0;
+3 -30
View File
@@ -5,7 +5,6 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_uid.sas @li mf_uid.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createfolder.sas @li mv_createfolder.sas
@li mv_deleteviyafolder.sas @li mv_deleteviyafolder.sas
@li mv_getfoldermembers.sas @li mv_getfoldermembers.sas
@@ -16,11 +15,7 @@
%let folder=%mf_uid(); %let folder=%mf_uid();
/* create a folder */ /* create a folder */
%mp_assertscope(SNAPSHOT)
%mv_createfolder(path=&mcTestAppLoc/temp/&folder/&folder) %mv_createfolder(path=&mcTestAppLoc/temp/&folder/&folder)
%mp_assertscope(COMPARE, ignorelist=MC0_JADP1LEN MC0_JADP2LEN MC0_JADPNUM
MC0_JADVLEN MC2_JADP1LEN MC2_JADP2LEN MC2_JADPNUM MC2_JADVLEN
)
%mv_getfoldermembers(root=&mcTestAppLoc/temp/&folder, outds=work.folders) %mv_getfoldermembers(root=&mcTestAppLoc/temp/&folder, outds=work.folders)
@@ -37,39 +32,17 @@ run;
) )
/* create a folder without output dataset as part of the original macro */ /* create a folder without output dataset as part of the original macro */
%mv_createfolder(path=&mcTestAppLoc/temp/&folder/f2 %mv_createfolder(path=&mcTestAppLoc/temp/&folder/folder2,outds=folders2)
,outds=folders2,mdebug=&sasjs_mdebug
)
%let test=0; %let test=0;
data _null_; data _null_;
set work.folders2; set work.folders2;
putlog (_all_)(=); putlog (_all_)(=);
if not missing(self_uri) then call symputx('test2',1); if not missing(self_uri) and not missing(parent_uri)
then call symputx('test2',1);
run; run;
%mp_assert( %mp_assert(
iftrue=(&test2=1), iftrue=(&test2=1),
desc=Check if outds param works desc=Check if outds param works
) )
/* create a folder with full stops */
%let newfolder=%mf_uid().2.1;
%mv_createfolder(path=&mcTestAppLoc/temp/&newfolder
,outds=work.folders3
,mdebug=&sasjs_mdebug
)
%mv_getfoldermembers(root=&mcTestAppLoc/temp, outds=work.folders3)
%let test3=0;
data _null_;
set work.folders3;
putlog (_all_)(=);
if name="&newfolder" then call symputx('test3',1);
run;
%mp_assert(
iftrue=(&test3=1),
desc=Check if folder with full stops can be successfully created
)
+5 -5
View File
@@ -33,19 +33,19 @@ data _null_;
; ;
run; run;
%mv_createjob(path=&mcTestAppLoc,name=demo1,code=testprog) %mv_createjob(path=/Public/temp,name=demo1,code=testprog)
%mv_createjob(path=&mcTestAppLoc,name=demo2,code=testprog) %mv_createjob(path=/Public/temp,name=demo2,code=testprog)
data work.inputjobs; data work.inputjobs;
_contextName="&mcTestContext"; _contextName='SAS Job Execution compute context';
do flow_id=1 to 2; do flow_id=1 to 2;
do i=1 to 4; do i=1 to 4;
_program="&mcTestAppLoc/demo1"; _program='/Public/temp/demo1';
macrovar1=10*i; macrovar1=10*i;
macrovar2=4*i; macrovar2=4*i;
output; output;
i+1; i+1;
_program="&mcTestAppLoc/demo2"; _program='/Public/temp/demo2';
macrovar1=40*i; macrovar1=40*i;
macrovar2=44*i; macrovar2=44*i;
output; output;
+5 -5
View File
@@ -29,19 +29,19 @@ data _null_;
; ;
run; run;
%mv_createjob(path=&mcTestAppLoc,name=demo1,code=testprog) %mv_createjob(path=/Public/temp,name=demo1,code=testprog)
%mv_createjob(path=&mcTestAppLoc,name=demo2,code=testprog) %mv_createjob(path=/Public/temp,name=demo2,code=testprog)
data work.inputjobs; data work.inputjobs;
_contextName="&mcTestContext"; _contextName='SAS Job Execution compute context';
do flow_id=1 to 2; do flow_id=1 to 2;
do i=1 to 4; do i=1 to 4;
_program="&mcTestAppLoc/demo1"; _program='/Public/temp/demo1';
macrovar1=10*i; macrovar1=10*i;
macrovar2=4*i; macrovar2=4*i;
output; output;
i+1; i+1;
_program="&mcTestAppLoc/demo2"; _program='/Public/temp/demo2';
macrovar1=40*i; macrovar1=40*i;
macrovar2=44*i; macrovar2=44*i;
output; output;
-192
View File
@@ -1,192 +0,0 @@
/**
@file
@brief Testing mx_append2pgm.sas macro
Be sure to run <code>%let mcTestAppLoc=/Public/temp/macrocore;</code> when
running in Studio
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_uid.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li ms_createfile.sas
@li mv_createfile.sas
@li mm_createstp.sas
@li mx_append2pgm.sas
@li mx_getcode.sas
**/
/**
* Test 1 - Append content to an existing program and verify combined output
* Also checking for scope leakage
*/
/* create a unique name for the program */
%let item=test_%mf_uid();
/* create the initial program with some code */
filename initpgm temp;
data _null_;
file initpgm;
put '%put ORIGINAL LINE;';
run;
%macro setup_pgm();
%let platform=%mf_getplatform();
%if &platform=SASJS %then %do;
%ms_createfile(&mcTestAppLoc/temp/&item..sas, inref=initpgm)
%end;
%else %if &platform=SASVIYA %then %do;
%mv_createfile(path=&mcTestAppLoc/temp, name=&item..sas, inref=initpgm)
%end;
%else %do;
%let work=%sysfunc(pathname(work));
data _null_;
file "&work/&item..sas";
infile initpgm;
input;
put _infile_;
run;
%mm_createstp(stpname=&item
,filename=&item..sas
,directory=&work
,tree=&mcTestAppLoc/temp
,stptype=2
,minify=NO
)
%end;
%mend setup_pgm;
%setup_pgm()
/* create the content to append */
filename toappnd temp;
data _null_;
file toappnd;
put '%put APPENDED LINE;';
run;
/* run the macro under test with scope checks */
%mp_assertscope(SNAPSHOT)
%mx_append2pgm(&mcTestAppLoc/temp/&item, inref=toappnd)
%mp_assertscope(COMPARE,
desc=Test 1: mx_append2pgm does not leak scope,
outds=work.test_results,
ignorelist=MC2_JADP1LEN MC2_JADP2LEN MC2_JADPNUM MC2_JADVLEN MC2_JADP3LEN
)
%mp_assert(
iftrue=(&syscc=0),
desc=Test 1: No errors after appending content to program,
outds=work.test_results
)
/**
* Test 2 - Verify the appended content is present
* Fetch the modified program and check both original and appended lines exist
*/
%let test2_orig=0;
%let test2_appd=0;
%macro verify_test2();
%let platform=%mf_getplatform();
%if &platform=SASVIYA %then %do;
filename verifrf filesrvc folderpath="&mcTestAppLoc/temp";
data _null_;
infile verifrf("&item..sas") lrecl=32000;
input;
if index(_infile_,'ORIGINAL LINE') then call symputx('test2_orig','1');
if index(_infile_,'APPENDED LINE') then call symputx('test2_appd','1');
run;
filename verifrf clear;
%end;
%else %do;
%mx_getcode(&mcTestAppLoc/temp/&item, outref=verifrf)
data _null_;
infile verifrf lrecl=32000;
input;
if index(_infile_,'ORIGINAL LINE') then call symputx('test2_orig','1');
if index(_infile_,'APPENDED LINE') then call symputx('test2_appd','1');
run;
%end;
%mend verify_test2;
%verify_test2()
%mp_assert(
iftrue=(&test2_orig=1),
desc=Test 2a: Original content is preserved after append,
outds=work.test_results
)
%mp_assert(
iftrue=(&test2_appd=1),
desc=Test 2b: Appended content is present in modified program,
outds=work.test_results
)
/**
* Test 3 - Append multiple times to ensure repeated appends work
*/
filename toappd2 temp;
data _null_;
file toappd2;
put '%put SECOND APPEND;';
run;
%mp_assertscope(SNAPSHOT)
%mx_append2pgm(&mcTestAppLoc/temp/&item, inref=toappd2)
%mp_assertscope(COMPARE,
desc=Test 3: mx_append2pgm does not leak scope on second call,
outds=work.test_results
)
/* verify all three pieces of content exist */
%let test3_orig=0;
%let test3_appd=0;
%let test3_app2=0;
%macro verify_test3();
%let platform=%mf_getplatform();
%if &platform=SASVIYA %then %do;
filename verifr2 filesrvc folderpath="&mcTestAppLoc/temp";
data _null_;
infile verifr2("&item..sas") lrecl=32000;
input;
if index(_infile_,'ORIGINAL LINE') then call symputx('test3_orig','1');
if index(_infile_,'APPENDED LINE') then call symputx('test3_appd','1');
if index(_infile_,'SECOND APPEND') then call symputx('test3_app2','1');
run;
filename verifr2 clear;
%end;
%else %do;
%mx_getcode(&mcTestAppLoc/temp/&item, outref=verifr2)
data _null_;
infile verifr2 lrecl=32000;
input;
if index(_infile_,'ORIGINAL LINE') then call symputx('test3_orig','1');
if index(_infile_,'APPENDED LINE') then call symputx('test3_appd','1');
if index(_infile_,'SECOND APPEND') then call symputx('test3_app2','1');
run;
%end;
%mend verify_test3;
%verify_test3()
%mp_assert(
iftrue=(&test3_orig=1),
desc=Test 3a: Original content still present after second append,
outds=work.test_results
)
%mp_assert(
iftrue=(&test3_appd=1),
desc=Test 3b: First appended content still present after second append,
outds=work.test_results
)
%mp_assert(
iftrue=(&test3_app2=1),
desc=Test 3c: Second appended content is present,
outds=work.test_results
)
+9 -8
View File
@@ -6,12 +6,12 @@
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!; %if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
The function uses `dosubl()` to run the `table.fileinfo` action, for the The function uses `dosubl()` to run the `table.fileinfo` action, for the
specified library, filtering for `*.sashdat` tables. specified library, filtering for `*.sashdat` tables. The results are stored
in a WORK table (&outprefix._&lib). If that table already exists, it is
queried instead, to avoid the dosubl() performance hit.
Results are cached in a WORK table (&outprefix._&lib). If that table To force a rescan, just use a new `&outprefix` value, or delete the table(s)
already exists it is queried directly to avoid the dosubl() overhead. before running the function.
To force a rescan, use a new `&outprefix` value or delete the cache
table before calling.
@param [in] libds library.dataset @param [in] libds library.dataset
@param [out] outprefix= (work.mfv_existsashdat) @param [out] outprefix= (work.mfv_existsashdat)
@@ -24,12 +24,13 @@
@author Mathieu Blauw @author Mathieu Blauw
**/ **/
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat); %macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
);
%local rc dsid name lib ds; %local rc dsid name lib ds;
%let lib=%upcase(%scan(&libds,1,'.')); %let lib=%upcase(%scan(&libds,1,'.'));
%let ds=%upcase(%scan(&libds,-1,'.')); %let ds=%upcase(%scan(&libds,-1,'.'));
/* if cache table does not exist, build it */ /* if table does not exist, create it */
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do; %if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
%let rc=%sysfunc(dosubl(%nrstr( %let rc=%sysfunc(dosubl(%nrstr(
/* Read in table list (once per &lib per session) */ /* Read in table list (once per &lib per session) */
@@ -40,7 +41,7 @@
quit; quit;
/* Only keep name, without file extension */ /* Only keep name, without file extension */
data &outprefix._&lib; data &outprefix._&lib;
set &outprefix._&lib(where=(upcase(Name) like '%.SASHDAT') keep=Name); set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
Name=upcase(scan(Name,1,'.')); Name=upcase(scan(Name,1,'.'));
run; run;
))); )));
-37
View File
@@ -1,37 +0,0 @@
/**
@file mfv_getcaslib.sas
@brief Returns the CAS caslib name for a given SAS libref
@details Pure macro function. Reads sashelp.vlibnam and returns
the sysvalue where sysname='Caslib' for the given libref. This
is useful when the caslib name and libref name may differ.
Usage:
%put %mfv_getcaslib(lib=PUBLIC);
@param [in] lib SAS libref for which to return the CAS caslib name
@return Returns the CAS caslib name, or empty string if not found
**/
%macro mfv_getcaslib(lib);
%local dsid rc result;
%let dsid=%sysfunc(open(sashelp.vlibnam(
where=(libname="%upcase(&lib)" and sysname="Caslib")
)));
%if &dsid %then %do;
%let rc=%sysfunc(fetch(&dsid));
%if &rc=0 %then
%let result=%sysfunc(
getvarc(&dsid,%sysfunc(varnum(&dsid,SYSVALUE)))
);
%let rc=%sysfunc(close(&dsid));
%end;
&result
%mend mfv_getcaslib;
-207
View File
@@ -1,207 +0,0 @@
/**
@file mv_castabload.sas
@brief Checks if a CAS table is loaded; if not, loads and promotes it
@details Runs in SPRE against an active CAS session. Accepts a
SAS libref, derives the CAS caslib and session UUID from
sashelp.vlibnam, then checks whether the table is already
in-memory. If not, locates the owning CAS server via the
casManagement REST API, queries the table endpoint to discover
the source file and caslib, then loads and promotes the table.
A CAS session must already be established by the caller, eg:
cas mysess;
libname mylib cas caslib=Public;
%mv_castabload(lib=mylib, table=BASEBALL)
@param [in] lib= SAS libref for the CAS caslib
@param [in] table= Name of the CAS table to load
@param [in] mdebug= (0) Set to 1 to enable verbose logging:
- echoes resolved parameters
- prints tableExists result
- enables mprint/notes during PROC calls
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mp_abort.sas
**/
%macro mv_castabload(
lib=
,table=
,mdebug=0
);
%local _sysopts base_uri caslib uuid server
srcfile srccaslib fname1 libref1 ftmp i _svcount _exists;
%let _sysopts=%sysfunc(getoption(mprint)) %sysfunc(getoption(notes));
/* ---- input validation -------------------------------------------------- */
%mp_abort(
iftrue=("&lib"="" or "&table"=""),
msg=%str(lib= and table= are required)
)
%if &mdebug=1 %then %do;
%put &=lib;
%put &=table;
options mprint notes;
%end;
/* ---- derive caslib and session UUID from sashelp.vlibnam --------------- */
data _null_;
set sashelp.vlibnam(
where=(libname="%upcase(&lib)"
and sysname in ("Caslib","Session UUID"))
);
if sysname="Caslib" then call symputx('caslib',sysvalue,'L');
else call symputx('uuid',sysvalue,'L');
%if &mdebug=1 %then %do;
putlog sysname sysvalue;
%end;
run;
%mp_abort(
iftrue=("&caslib"=""),
msg=%str(&lib is not an assigned CAS libref)
)
%mp_abort(
iftrue=("&uuid"=""),
msg=%str(No session UUID found for libref &lib)
)
/* ---- existence check --------------------------------------------------- */
proc cas;
table.tableExists result=r /
caslib="&caslib"
name="&table";
%if &mdebug=1 %then %do;
print r;
%end;
if r.exists > 0 then call symputx('_exists', '1', 'L');
else call symputx('_exists', '0', 'L');
quit;
/* ---- already loaded: skip ---------------------------------------------- */
%if &_exists=1 %then %do;
%put NOTE: Table &caslib..&table already loaded - skipping;
%return;
%end;
/* ---- get list of CAS servers ----------------------------------------- */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref();
proc http method='GET' out=&fname1 oauth_bearer=sas_services
url="&base_uri/casManagement/servers";
run;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200),
msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..items;
call symputx(cats('_sv_', _n_), name, 'L');
call symputx('_svcount', _n_, 'L');
run;
libname &libref1 clear;
filename &fname1 clear;
/* ---- find which server owns this session ------------------------------ */
%do i=1 %to &_svcount;
%if "&server"="" %then %do;
%if &mdebug=1 %then %put checking server: &&_sv_&i;
%let ftmp=%mf_getuniquefileref();
proc http method='GET' out=&ftmp oauth_bearer=sas_services
url="&base_uri/casManagement/servers/&&_sv_&i/sessions/&uuid";
run;
%if &SYS_PROCHTTP_STATUS_CODE=200
%then %let server=&&_sv_&i;
filename &ftmp clear;
%end;
%end;
%mp_abort(
iftrue=("&server"=""),
msg=%str(Could not find owning server for CAS session &uuid)
)
%if &mdebug=1 %then %put &=server;
/* ---- discover source file from REST endpoint -------------------------- */
%let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref();
proc http method='GET' out=&fname1 oauth_bearer=sas_services
url="&base_uri/casManagement/servers/&server/caslibs/&caslib/tables/&table";
run;
%if &mdebug=1 %then %do;
%put &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
data _null_;
infile &fname1;
input;
putlog _infile_;
run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE=404),
msg=%str(&caslib..&table not found - is a source file registered?)
)
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200),
msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..tablereference;
call symputx('srcfile', sourceTableName, 'L');
call symputx('srccaslib', sourceCaslibName, 'L');
stop;
run;
libname &libref1 clear;
filename &fname1 clear;
%mp_abort(
iftrue=("&srcfile"="" or "&srccaslib"=""),
msg=%str(No sourceTableName/sourceCaslibName for &caslib..&table)
)
%if &mdebug=1 %then %put &=srcfile &=srccaslib;
/* ---- load from discovered source -------------------------------------- */
proc casutil;
load casdata="&srcfile"
incaslib="&srccaslib"
casout="&table"
outcaslib="&caslib"
promote;
quit;
%mp_abort(
iftrue=(&syscc ne 0),
msg=%str(Load failed for &caslib..&table)
)
%put NOTE: Table &caslib..&table loaded and promoted from &srcfile;
/* ---- restore options --------------------------------------------------- */
%if &mdebug=1 %then %do;
options &_sysopts;
%end;
%mend mv_castabload;
-192
View File
@@ -1,192 +0,0 @@
/**
@file mv_castabsave.sas
@brief Saves an in-memory CAS table back to persistent storage
@details Runs in SPRE against an active CAS session. Accepts a
SAS libref, derives the CAS caslib and session UUID from
sashelp.vlibnam, locates the owning CAS server via the
casManagement REST API, then queries the table endpoint to
discover the original source file and saves back to that path.
CASUTIL infers the file type from the output file extension.
A CAS session must already be established by the caller, eg:
cas mysess;
libname mylib cas caslib=Public;
%mv_castabsave(lib=mylib, table=BASEBALL)
@param [in] lib= SAS libref for the CAS caslib
@param [in] table= Name of the in-memory CAS table to save
@param [in] mdebug= (0) Set to 1 to enable verbose logging:
- echoes resolved parameters
- prints HTTP response body
- enables mprint/notes during PROC calls
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mp_abort.sas
**/
%macro mv_castabsave(
lib=
,table=
,mdebug=0
);
%local _sysopts base_uri caslib uuid server
srcfile srccaslib fname1 libref1 ftmp i _svcount;
%let _sysopts=%sysfunc(getoption(mprint)) %sysfunc(getoption(notes));
/* ---- input validation -------------------------------------------------- */
%mp_abort(
iftrue=("&lib"="" or "&table"=""),
msg=%str(lib= and table= are required)
)
%if &mdebug=1 %then %do;
%put &=lib;
%put &=table;
options mprint notes;
%end;
/* ---- derive caslib and session UUID from sashelp.vlibnam --------------- */
data _null_;
set sashelp.vlibnam(
where=(libname="%upcase(&lib)"
and sysname in ("Caslib","Session UUID"))
);
if sysname="Caslib" then call symputx('caslib',sysvalue,'L');
else call symputx('uuid',sysvalue,'L');
run;
%mp_abort(
iftrue=("&caslib"=""),
msg=%str(&lib is not an assigned CAS libref)
)
%mp_abort(
iftrue=("&uuid"=""),
msg=%str(No session UUID found for libref &lib)
)
%if &mdebug=1 %then %do;
%put &=caslib;
%put &=uuid;
%end;
%let base_uri=%mf_getplatform(VIYARESTAPI);
/* ---- get list of CAS servers ------------------------------------------- */
%let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref();
proc http method='GET' out=&fname1 oauth_bearer=sas_services
url="&base_uri/casManagement/servers";
run;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200),
msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..items;
call symputx(cats('_sv_', _n_), name, 'L');
call symputx('_svcount', _n_, 'L');
run;
libname &libref1 clear;
filename &fname1 clear;
/* ---- find which server owns this session ------------------------------- */
%do i=1 %to &_svcount;
%if "&server"="" %then %do;
%if &mdebug=1 %then %put checking server: &&_sv_&i;
%let ftmp=%mf_getuniquefileref();
proc http method='GET' out=&ftmp oauth_bearer=sas_services
url="&base_uri/casManagement/servers/&&_sv_&i/sessions/&uuid";
run;
%if &SYS_PROCHTTP_STATUS_CODE=200
%then %let server=&&_sv_&i;
filename &ftmp clear;
%end;
%end;
%mp_abort(
iftrue=("&server"=""),
msg=%str(Could not find owning server for CAS session &uuid)
)
%if &mdebug=1 %then %put &=server;
/* ---- discover srcfile from REST endpoint ------------------------------- */
%let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref();
proc http method='GET' out=&fname1 oauth_bearer=sas_services
url="&base_uri/casManagement/servers/&server/caslibs/&caslib/tables/&table";
run;
%if &mdebug=1 %then %do;
%put &=SYS_PROCHTTP_STATUS_CODE &=SYS_PROCHTTP_STATUS_PHRASE;
data _null_;
infile &fname1;
input;
putlog _infile_;
run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE=404),
msg=%str(&caslib..&table not found - is it loaded in memory?)
)
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200),
msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
libname &libref1 JSON fileref=&fname1;
data _null_;
set &libref1..tablereference;
call symputx('srcfile', sourceTableName, 'L');
call symputx('srccaslib', sourceCaslibName, 'L');
stop;
run;
libname &libref1 clear;
filename &fname1 clear;
%mp_abort(
iftrue=("&srcfile"="" or "&srccaslib"=""),
msg=%str(No sourceTableName/sourceCaslibName for &caslib..&table)
)
%if &mdebug=1 %then %put &=srcfile;
/* ---- save to disk ------------------------------------------------------- */
proc casutil;
save casdata="&table"
incaslib="&caslib"
casout="&srcfile"
outcaslib="&srccaslib"
replace;
quit;
%mp_abort(
iftrue=(&syscc ne 0),
msg=%str(Save failed for &caslib..&table)
)
%put NOTE: Table &caslib..&table saved to &srcfile;
/* ---- restore options --------------------------------------------------- */
%if &mdebug=1 %then %do;
options &_sysopts;
%end;
%mend mv_castabsave;
+2 -3
View File
@@ -206,8 +206,7 @@ run;
%mv_getViyaFileExtParms(&ext %mv_getViyaFileExtParms(&ext
,propertiesVar=viyaProperties ,propertiesVar=viyaProperties
,typeDefNameVar=viyaTypeDefName ,typeDefNameVar=viyaTypeDefName
,mdebug=&mdebug ,mdebug=&mdebug);
)
/* fetch job info */ /* fetch job info */
%local fname1; %local fname1;
@@ -297,7 +296,7 @@ run;
run; run;
%end; %end;
/* Apply the properties to the newly created file, using the PATCH method */ /* And apply the properties to the newly created file, using the PATCH method */
%let fref=%mf_getuniquefileref(); %let fref=%mf_getuniquefileref();
filename &fref "&viyapatch"; filename &fref "&viyapatch";
%let url=&base_uri&fileuri; %let url=&base_uri&fileuri;
+1
View File
@@ -145,6 +145,7 @@ options noquotelenmax;
run; run;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do; %if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
%*put &sysmacroname &newpath exists so grab the follow on link ;
data _null_; data _null_;
set &libref1..links; set &libref1..links;
if rel='createChild' then if rel='createChild' then
+6 -20
View File
@@ -594,14 +594,14 @@ data _null_;
put ' ,showmeta=N,maxobs=MAX,workobs=0 '; put ' ,showmeta=N,maxobs=MAX,workobs=0 ';
put '); '; put '); ';
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name '; put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
put ' sasjs_tables SYS_JES_JOB_URI _EXECUTIONTASKS; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=128; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
put ' '; put ' ';
put '%local i tempds table; '; put '%local i tempds table; ';
put '%let action=%upcase(&action); '; put '%let action=%upcase(&action); ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
put ' %if %upcase(&_omittextlog)=FALSE or %str(&_debug) ge 128 %then %do; '; put ' %if %upcase(&_omittextlog)=FALSE or %str(&_debug) ge 131 %then %do; ';
put ' options mprint notes mprintnest; '; put ' options mprint notes mprintnest; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
@@ -609,11 +609,6 @@ data _null_;
put ' %let _webin_file_count=%eval(&_webin_file_count+0); '; put ' %let _webin_file_count=%eval(&_webin_file_count+0); ';
put ' %let _webin_fileuri1=&_webin_fileuri; '; put ' %let _webin_fileuri1=&_webin_fileuri; ';
put ' %let _webin_name1=&_webin_name; '; put ' %let _webin_name1=&_webin_name; ';
put ' %if &_EXECUTIONTASKS=true %then %do; ';
put ' /* TODO - remove this once SAS Track CS0409737 is resolved */ ';
put ' /* links: https://github.com/sasjs/adapter/issues/884 */ ';
put ' %if %upcase(&_webin_name)=_SASJS_NOOP %then %let _webin_file_count=0; ';
put ' %end; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' /* if the sasjs_tables param is passed, we expect param based upload */ '; put ' /* if the sasjs_tables param is passed, we expect param based upload */ ';
@@ -654,17 +649,13 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' %else %do i=1 %to &_webin_file_count; '; put ' %else %do i=1 %to &_webin_file_count; ';
put ' /* read in any files that are sent */ '; put ' /* read in any files that are sent */ ';
put ' %if &_EXECUTIONTASKS=true %then %do; '; put ' /* this part needs refactoring for wide files */ ';
put ' filename indata "%sysfunc(pathname(&&_webin_fileref&i))" lrecl=999999; ';
put ' %end; ';
put ' %else %do; ';
put ' filename indata filesrvc "&&_webin_fileuri&i" lrecl=999999; '; put ' filename indata filesrvc "&&_webin_fileuri&i" lrecl=999999; ';
put ' %end; ';
put ' data _null_; '; put ' data _null_; ';
put ' infile indata termstr=crlf lrecl=32767; '; put ' infile indata termstr=crlf lrecl=32767; ';
put ' input; '; put ' input; ';
put ' if _n_=1 then call symputx(''input_statement'',_infile_); '; put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' %if %str(&_debug) ge 128 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
put ' if _n_<20 then putlog _infile_; '; put ' if _n_<20 then putlog _infile_; ';
put ' else stop; '; put ' else stop; ';
put ' %end; '; put ' %end; ';
@@ -697,9 +688,6 @@ data _null_;
put ' '; put ' ';
put ' /* setup json */ '; put ' /* setup json */ ';
put ' data _null_;file &fref; '; put ' data _null_;file &fref; ';
put ' %if %str(&_debug) ge 128 and &_EXECUTIONTASKS=true %then %do; ';
put ' put ''>>weboutBEGIN<<''; ';
put ' %end; ';
put ' put ''{"SYSDATE" : "'' "&SYSDATE" ''"''; '; put ' put ''{"SYSDATE" : "'' "&SYSDATE" ''"''; ';
put ' put '',"SYSTIME" : "'' "&SYSTIME" ''"''; '; put ' put '',"SYSTIME" : "'' "&SYSTIME" ''"''; ';
put ' run; '; put ' run; ';
@@ -812,9 +800,7 @@ data _null_;
put ' memsize=quote(cats(memsize)); '; put ' memsize=quote(cats(memsize)); ';
put ' put '',"MEMSIZE" : '' memsize; '; put ' put '',"MEMSIZE" : '' memsize; ';
put ' put "}"; '; put ' put "}"; ';
put ' %if %str(&_debug) ge 128 and &_EXECUTIONTASKS=true %then %do; '; put ' ';
put ' put ''>>weboutEND<<''; ';
put ' %end; ';
put ' %if %upcase(&fref) ne _WEBOUT and &stream=Y %then %do; '; put ' %if %upcase(&fref) ne _WEBOUT and &stream=Y %then %do; ';
put ' data _null_; rc=fcopy("&fref","_webout");run; '; put ' data _null_; rc=fcopy("&fref","_webout");run; ';
put ' %end; '; put ' %end; ';
+23 -30
View File
@@ -23,7 +23,6 @@
@li mf_existds.sas @li mf_existds.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvalue.sas @li mf_getvalue.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@@ -49,7 +48,7 @@
iftrue=(%mf_isBlank(&ext)) iftrue=(%mf_isBlank(&ext))
,msg=%str(No file extension provided.) ,msg=%str(No file extension provided.)
,mac=MV_GETVIYAFILEEXTPARMS ,mac=MV_GETVIYAFILEEXTPARMS
) );
%mp_abort( %mp_abort(
iftrue=(%mf_isBlank(&typeDefNameVar) and iftrue=(%mf_isBlank(&typeDefNameVar) and
@@ -57,13 +56,13 @@
%mf_isBlank(&mediaTypeVar)) %mf_isBlank(&mediaTypeVar))
,msg=%str(MV_GETVIYAFILEEXTPARMS - No parameter was requested.) ,msg=%str(MV_GETVIYAFILEEXTPARMS - No parameter was requested.)
,mac=MV_GETVIYAFILEEXTPARMS ,mac=MV_GETVIYAFILEEXTPARMS
) );
%mp_abort( %mp_abort(
iftrue=(%mf_isBlank(&viyaFileExtRespLibDs)) iftrue=(%mf_isBlank(&viyaFileExtRespLibDs))
,msg=%str(No <libname.>dataset name provided to cache inital response.) ,msg=%str(No <libname.>dataset name provided to cache inital response.)
,mac=MV_GETVIYAFILEEXTPARMS ,mac=MV_GETVIYAFILEEXTPARMS
) );
/* Declare requested parameters as global macro vars and initialize blank */ /* Declare requested parameters as global macro vars and initialize blank */
%if not %mf_isBlank(&typeDefNameVar) %then %do; %if not %mf_isBlank(&typeDefNameVar) %then %do;
@@ -80,7 +79,9 @@
%end; %end;
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
%if &mdebug=1 %then %put DEBUG: &=base_uri; %if &mdebug=1 %then %do;
%put DEBUG: &=base_uri;
%end;
%let ext=%lowcase(&ext); %let ext=%lowcase(&ext);
@@ -104,7 +105,7 @@
%if (&SYS_PROCHTTP_STATUS_CODE ne 200) %then %do; %if (&SYS_PROCHTTP_STATUS_CODE ne 200) %then %do;
/* To avoid a breaking change, exit early if the request failed. /* To avoid a breaking change, exit early if the request failed.
The calling process will proceed with empty macro variables. */ The calling process will proceed with empty requested macro variables. */
%put INFO: &sysmacroname File extension details were not retrieved.; %put INFO: &sysmacroname File extension details were not retrieved.;
filename &viyatypedefs clear; filename &viyatypedefs clear;
%return; %return;
@@ -125,12 +126,11 @@
/* Convert the content of that JSON into SAS datasets */ /* Convert the content of that JSON into SAS datasets */
/* First prepare a new WORK-based folder to receive the datasets */ /* First prepare a new WORK-based folder to receive the datasets */
%local jsonworkfolder jsonlib opt_dlcreatedir; %local jsonworkfolder jsonlib opt_dlcreatedir;
%let jsonworkfolder=%sysfunc(pathname(work))/%mf_getuniquename(prefix=jsn_); %let jsonworkfolder=%sysfunc(pathname(work))/%mf_getuniquename(prefix=json_);
%let jsonlib=%mf_getuniquelibref(prefix=json); %let jsonlib=%mf_getuniquelibref(prefix=json);
/* And point a libname at it */ /* And point a libname at it */
%let opt_dlcreatedir = %sysfunc(getoption(dlcreatedir)); %let opt_dlcreatedir = %sysfunc(getoption(dlcreatedir));
options dlcreatedir; libname &jsonlib "&jsonworkfolder"; options dlcreatedir; libname &jsonlib "&jsonworkfolder"; options &opt_dlcreatedir;
options &opt_dlcreatedir;
/* Read the json output once and copy datasets to its work folder */ /* Read the json output once and copy datasets to its work folder */
%local libref1; %local libref1;
@@ -159,22 +159,20 @@
%end; /* If initial filetype query response didn't exist */ %end; /* If initial filetype query response didn't exist */
%if &mdebug %then %put DEBUG: Find the row-group for extension &ext; /* Find the row-group for the current file extension */
%local itemRowGroup; %local itemRowGroup;
data _null_; %let itemRowGroup =
set &viyaFileExtRespLibDs; %mf_getValue(
where p1='items' and p2='extensions' and value="&ext"; &viyaFileExtRespLibDs
call symputx('itemRowGroup',_viyaItemIdx,'l'); ,_viyaItemIdx
%if &mdebug %then %do; ,filter=%quote(p1='items' and p2='extensions' and value="&ext")
putlog (_all_)(=); );
%end;
run;
%if &mdebug %then %put DEBUG: &=itemRowGroup; %if &mdebug %then %put DEBUG: &=itemRowGroup;
%if %mf_isBlank(&itemRowGroup) %then %do; %if %mf_isBlank(&itemRowGroup) %then %do;
/* extension was not found */ /* extension was not found */
%if &mdebug %then %put DEBUG: No type details found for extension "&ext"; %if(&mdebug=1) %then %put DEBUG: No type details found for extension "&ext".;
%return; %return;
%end; %end;
@@ -188,17 +186,14 @@
/* Populate typeDefName, if requested */ /* Populate typeDefName, if requested */
%if (not %mf_isBlank(&typeDefNameVar)) %then %do; %if (not %mf_isBlank(&typeDefNameVar)) %then %do;
%let &typeDefNameVar = %mf_getvalue( %let &typeDefNameVar = %mf_getvalue(&dsItems,value,filter=%quote(p1="items" and p2="name"));
&dsItems,value,filter=%quote(p1="items" and p2="name")); %if &mdebug=1 %then %put DEBUG: &=typeDefNameVar &typeDefNameVar=&&&typeDefNameVar;
%if &mdebug %then
%put DEBUG: &=typeDefNameVar &typeDefNameVar=&&&typeDefNameVar;
%end; %end;
/* Populate mediaType, if requested */ /* Populate mediaType, if requested */
%if (not %mf_isBlank(&mediaTypeVar)) %then %do; %if (not %mf_isBlank(&mediaTypeVar)) %then %do;
%let &mediaTypeVar = %mf_getvalue( %let &mediaTypeVar = %mf_getvalue(&dsItems,value,filter=%quote(p1="items" and p2="mediaType"));
&dsItems,value,filter=%quote(p1="items" and p2="mediaType")); %if &mdebug=1 %then %put DEBUG: &=mediaTypeVar &mediaTypeVar=&&&mediaTypeVar;
%if &mdebug %then %put DEBUG: &=mediaTypeVar &mediaTypeVar=&&&mediaTypeVar;
%end; %end;
/* Populate properties macro variable, if requested */ /* Populate properties macro variable, if requested */
@@ -215,8 +210,7 @@
/* Check for 1+ properties */ /* Check for 1+ properties */
%if ( %mf_nobs(&dsProperties) = 0 ) %then %do; %if ( %mf_nobs(&dsProperties) = 0 ) %then %do;
%let &propertiesVar = %str(); %let &propertiesVar = %str();
%if &mdebug %then %put DEBUG: &SYSMACRONAME - No Viya properties %trim( %if &mdebug=1 %then %put DEBUG: &SYSMACRONAME - No Viya properties found for file suffix %str(%')&ext%str(%');
)found for file suffix %str(%')&ext%str(%');
%end; %end;
%else %do; %else %do;
/* Properties potentially span multiple rows in the input table */ /* Properties potentially span multiple rows in the input table */
@@ -246,8 +240,7 @@
end; end;
run; run;
%if &mdebug %then %if &mdebug=1 %then %put DEBUG: &=propertiesVar &propertiesVar=&&&propertiesVar;
%put DEBUG: &=propertiesVar &propertiesVar=&&&propertiesVar;
%end; %end;
%end; %end;
+18 -33
View File
@@ -121,7 +121,7 @@
@li mf_nobs.sas @li mf_nobs.sas
@li mp_abort.sas @li mp_abort.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getvarlist.sas @li mf_getuniquefileref.sas
@li mf_existvarlist.sas @li mf_existvarlist.sas
@li mv_jobwaitfor.sas @li mv_jobwaitfor.sas
@li mv_jobexecute.sas @li mv_jobexecute.sas
@@ -234,12 +234,14 @@ data _null_;
if last then call symputx('flowcnt',cnt,'l'); if last then call symputx('flowcnt',cnt,'l');
run; run;
/* prepare temporary datasets */ /* prepare temporary datasets and frefs */
%local fid jid jds jdsapp jdsrunning jdswaitfor; %local fid jid jds jjson jdsapp jdsrunning jdswaitfor jfref;
data;run;%let jds=&syslast; data;run;%let jds=&syslast;
data;run;%let jjson=&syslast;
data;run;%let jdsapp=&syslast; data;run;%let jdsapp=&syslast;
data;run;%let jdsrunning=&syslast; data;run;%let jdsrunning=&syslast;
data;run;%let jdswaitfor=&syslast; data;run;%let jdswaitfor=&syslast;
%let jfref=%mf_getuniquefileref();
/* start loop */ /* start loop */
%do fid=1 %to &flowcnt; %do fid=1 %to &flowcnt;
@@ -257,39 +259,23 @@ data;run;%let jdswaitfor=&syslast;
&dbg. if _n_= 1 then putlog "Loop &fid"; &dbg. if _n_= 1 then putlog "Loop &fid";
&dbg. putlog (_all_)(=); &dbg. putlog (_all_)(=);
run; run;
/* build list of char and num vars in json format */
/* Viya 2026 expects all values to be strings */
%local nvars cvars ii _vnm;
%let cvars=%mf_getvarlist(&jds,typefilter=C);
%let nvars=%mf_getvarlist(&jds,typefilter=N);
%put exporting job variables in json format; %put exporting job variables in json format;
%do jid=1 %to &jcnt; %do jid=1 %to &jcnt;
data _null_; data &jjson;
set &jds; set &jds;
if _n_=&jid; if _n_=&jid then do;
length _param $32767; output;
_param='';
%if %length(&cvars)>0 %then %do ii=1 %to %sysfunc(countw(&cvars,%str( )));
%let _vnm=%scan(&cvars,&ii,%str( ));
if _param ne '' then _param=cats(_param,',');
_param=cats(_param,'"'
,"%lowcase(&_vnm)"
,'":'
,quote(trim(&_vnm))
);
%end;
%if %length(&nvars)>0 %then %do ii=1 %to %sysfunc(countw(&nvars,%str( )));
%let _vnm=%scan(&nvars,&ii,%str( ));
if _param ne '' then _param=cats(_param,',');
_param=cats(_param,'"'
,"%lowcase(&_vnm)"
,'":"'
,strip(put(&_vnm,best32.))
,'"'
);
%end;
call symputx(cats('jparams',&jid),_param,'l');
stop; stop;
end;
run;
proc json out=&jfref;
export &jjson / nosastags fmtnumeric;
run;
data _null_;
infile &jfref lrecl=32767;
input;
jparams=cats('jparams',symget('jid'));
call symputx(jparams,substr(_infile_,3,length(_infile_)-4));
run; run;
%local jobuid&jid; %local jobuid&jid;
%let jobuid&jid=0; /* used in next loop */ %let jobuid&jid=0; /* used in next loop */
@@ -334,7 +320,6 @@ data;run;%let jdswaitfor=&syslast;
,paramstring=%superq(jparams&jid) ,paramstring=%superq(jparams&jid)
,outds=&jdsapp ,outds=&jdsapp
,contextname=&&context&jid ,contextname=&&context&jid
,mdebug=&mdebug
) )
data &jdsapp; data &jdsapp;
format jobparams $32767.; format jobparams $32767.;
+6 -20
View File
@@ -55,14 +55,14 @@
,showmeta=N,maxobs=MAX,workobs=0 ,showmeta=N,maxobs=MAX,workobs=0
); );
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name %global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
sasjs_tables SYS_JES_JOB_URI _EXECUTIONTASKS; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=128; %if %index("&_debug",log) %then %let _debug=131;
%local i tempds table; %local i tempds table;
%let action=%upcase(&action); %let action=%upcase(&action);
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
%if %upcase(&_omittextlog)=FALSE or %str(&_debug) ge 128 %then %do; %if %upcase(&_omittextlog)=FALSE or %str(&_debug) ge 131 %then %do;
options mprint notes mprintnest; options mprint notes mprintnest;
%end; %end;
@@ -70,11 +70,6 @@
%let _webin_file_count=%eval(&_webin_file_count+0); %let _webin_file_count=%eval(&_webin_file_count+0);
%let _webin_fileuri1=&_webin_fileuri; %let _webin_fileuri1=&_webin_fileuri;
%let _webin_name1=&_webin_name; %let _webin_name1=&_webin_name;
%if &_EXECUTIONTASKS=true %then %do;
/* TODO - remove this once SAS Track CS0409737 is resolved */
/* links: https://github.com/sasjs/adapter/issues/884 */
%if %upcase(&_webin_name)=_SASJS_NOOP %then %let _webin_file_count=0;
%end;
%end; %end;
/* if the sasjs_tables param is passed, we expect param based upload */ /* if the sasjs_tables param is passed, we expect param based upload */
@@ -115,17 +110,13 @@
%end; %end;
%else %do i=1 %to &_webin_file_count; %else %do i=1 %to &_webin_file_count;
/* read in any files that are sent */ /* read in any files that are sent */
%if &_EXECUTIONTASKS=true %then %do; /* this part needs refactoring for wide files */
filename indata "%sysfunc(pathname(&&_webin_fileref&i))" lrecl=999999;
%end;
%else %do;
filename indata filesrvc "&&_webin_fileuri&i" lrecl=999999; filename indata filesrvc "&&_webin_fileuri&i" lrecl=999999;
%end;
data _null_; data _null_;
infile indata termstr=crlf lrecl=32767; infile indata termstr=crlf lrecl=32767;
input; input;
if _n_=1 then call symputx('input_statement',_infile_); if _n_=1 then call symputx('input_statement',_infile_);
%if %str(&_debug) ge 128 %then %do; %if %str(&_debug) ge 131 %then %do;
if _n_<20 then putlog _infile_; if _n_<20 then putlog _infile_;
else stop; else stop;
%end; %end;
@@ -158,9 +149,6 @@
/* setup json */ /* setup json */
data _null_;file &fref; data _null_;file &fref;
%if %str(&_debug) ge 128 and &_EXECUTIONTASKS=true %then %do;
put '>>weboutBEGIN<<';
%end;
put '{"SYSDATE" : "' "&SYSDATE" '"'; put '{"SYSDATE" : "' "&SYSDATE" '"';
put ',"SYSTIME" : "' "&SYSTIME" '"'; put ',"SYSTIME" : "' "&SYSTIME" '"';
run; run;
@@ -273,9 +261,7 @@
memsize=quote(cats(memsize)); memsize=quote(cats(memsize));
put ',"MEMSIZE" : ' memsize; put ',"MEMSIZE" : ' memsize;
put "}"; put "}";
%if %str(&_debug) ge 128 and &_EXECUTIONTASKS=true %then %do;
put '>>weboutEND<<';
%end;
%if %upcase(&fref) ne _WEBOUT and &stream=Y %then %do; %if %upcase(&fref) ne _WEBOUT and &stream=Y %then %do;
data _null_; rc=fcopy("&fref","_webout");run; data _null_; rc=fcopy("&fref","_webout");run;
%end; %end;
-149
View File
@@ -1,149 +0,0 @@
/**
@file
@brief Appends a text file to a SASjs Stored Program, Viya SAS program, or
SAS 9 Stored Process
@details Extracts the source code from a SASjs Stored Program, Viya SAS
program (file in SAS Drive), or SAS 9 Stored Process, appends the contents
of a provided text file, then deletes and recreates the target item with the
combined content.
This is useful for dynamically modifying deployed programs, for example to
add test-specific configuration or runtime settings.
Usage:
%* compile macros ;
filename mc url
"https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* write some content to append;
filename append temp;
data _null_;
file append;
put "libname mylib '/some/path';";
run;
%* append to existing program;
%mx_append2pgm(/Public/app/common/settings, inref=append)
@param [in] loc The full path to the Viya SAS program, SAS 9 Stored Process,
or SASjs Stored Program in Drive or Metadata, WITHOUT the .sas extension
(SASjs only)
@param [in] inref= (0) Fileref pointing to the content to be appended to the
target program.
@param [in] mdebug= (0) Set to 1 to show debug messages in the log
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
@li mm_createstp.sas
@li mm_deletestp.sas
@li mm_getstpcode.sas
@li ms_createfile.sas
@li ms_deletefile.sas
@li mv_createfile.sas
@li mv_deletefoldermember.sas
@li mx_getcode.sas
<h4> Related Macros </h4>
@li mx_append2pgm.test.sas
@li mx_getcode.sas
@li mx_createjob.sas
@author Allan Bowe
**/
%macro mx_append2pgm(loc
,inref=0
,mdebug=0
)/*/STORE SOURCE*/;
%local platform name shortloc coderef combref work tmpfile viyaref;
%let platform=%mf_getplatform();
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%if &syscc ne 0 %then %do;
%put syscc=&syscc - &sysmacroname will not execute in this state;
%return;
%end;
/* extract name & path from loc */
data _null_;
length name shortloc $500;
loc=symget('loc');
name=scan(loc,-1,'/');
shortloc=substr(loc,1,length(loc)-length(name)-1);
call symputx('name',name,'l');
call symputx('shortloc',shortloc,'l');
run;
/* create a combined fileref with original + appended content */
%let combref=%mf_getuniquefileref();
%let work=%sysfunc(pathname(work));
%let tmpfile=&combref..sas;
filename &combref "&work/&tmpfile" lrecl=32000;
%if &platform=SASVIYA %then %do;
/* On Viya, read the SAS program file from SAS Drive using filesrvc */
%let viyaref=%mf_getuniquefileref();
filename &viyaref filesrvc folderpath="&shortloc";
data _null_;
file &combref lrecl=32000 termstr=crlf;
infile &viyaref("&name..sas") lrecl=32000 end=last;
input;
put _infile_;
run;
filename &viyaref clear;
%symdel _FILESRVC_&viyaref._URI;
%end;
%else %do;
/* For SAS9 and SASJS, use mx_getcode */
%let coderef=%mf_getuniquefileref();
%mx_getcode(&loc, outref=&coderef)
data _null_;
file &combref lrecl=32000 termstr=crlf;
infile &coderef lrecl=32000 end=last;
input;
put _infile_;
run;
filename &coderef clear;
%end;
/* append the new content */
data _null_;
file &combref lrecl=32000 termstr=crlf mod;
infile &inref lrecl=32000;
input;
put _infile_;
run;
/* delete and recreate the target item */
%if &platform=SASJS %then %do;
%ms_deletefile(&loc..sas)
%ms_createfile(&loc..sas, inref=&combref, mdebug=&mdebug)
%end;
%else %if &platform=SASVIYA %then %do;
%mv_deletefoldermember(path=&shortloc, name=&name..sas, contenttype=file)
%mv_createfile(path=&shortloc, name=&name..sas, inref=&combref)
%end;
%else %do;
/* SAS 9 */
%mm_deletestp(target=&loc)
%mm_createstp(stpname=&name
,filename=&tmpfile
,directory=&work
,tree=&shortloc
,stptype=2
,mDebug=&mdebug
,minify=NO
)
%end;
filename &combref clear;
%mend mx_append2pgm;