1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-11 06:24:35 +00:00

Compare commits

...

52 Commits

Author SHA1 Message Date
Allan Bowe
818bc3cc2b Merge pull request #244 from sasjs/getcode
feat: creating new mx_ suite of macros!
2022-05-20 13:18:16 +03:00
munja
bb6111e2b3 fix: all.sas, readme, dependency issue and sasjsconfig file 2022-05-20 11:16:30 +01:00
munja
512f05c0b2 feat: creating new mx_ suite of macros!
also adding new mx_getcode macro
2022-05-19 22:02:19 +01:00
Allan Bowe
500fb8124f Merge pull request #243 from sasjs/resetoption
fix: resetoption
2022-05-19 14:28:56 +03:00
Allan Bowe
88ddba2a4b fix: runall 2022-05-19 11:27:39 +00:00
Allan Bowe
86f6d06b85 fix: update resetoption and adding test 2022-05-19 11:26:55 +00:00
Allan Bowe
1cefc0e7ee feat: adding check in mf_existfeature() for ability to proc export xlsx 2022-05-18 15:33:41 +00:00
munja
412182a022 fix: fileref option in ms_runstp 2022-05-17 22:27:39 +01:00
Allan Bowe
43b8ee1c7e Merge pull request #242 from sasjs/ms_getgroups
Two new sasjs/server macros and associated tests
2022-05-17 18:05:05 +03:00
Allan Bowe
83eea02240 chore: updating all.sas 2022-05-17 15:03:36 +00:00
Allan Bowe
a14e31804a chore: fix test 2022-05-17 15:01:28 +00:00
Allan Bowe
3fa639ebf7 fix: tests for ms_creategroup 2022-05-17 14:56:11 +00:00
Allan
ed11d44fe8 feat: ms_creategroup and ms_getgroups macros with associated tests 2022-05-17 14:40:38 +00:00
Allan
de4ea8888f fix: updating mp_ds2md to cope with tables with no columns 2022-05-17 14:34:33 +00:00
Allan
ea0a936871 fix: adding codespaces config 2022-05-17 14:34:10 +00:00
Allan Bowe
042987c91e Merge pull request #241 from sasjs/copyfolder_enhancement
feat: Adding copymax parameter
2022-05-17 11:55:52 +03:00
Allan Bowe
6669e74baa chore: running all.sas and updating docs 2022-05-17 08:55:02 +00:00
Ivor Townsend
906f9a139d feat: Adding copymax parameter 2022-05-17 08:53:06 +01:00
Allan Bowe
b31f960635 Merge pull request #240 from sasjs/allanbowe/error-the-function-md-239
fix: avoiding use of md5() in sysfunc().  Closes #239
2022-05-12 13:35:08 +03:00
Allan Bowe
1ed3cb31b5 fix: put wrapper 2022-05-12 10:17:37 +00:00
Allan Bowe
ca7c332f20 fix: avoiding use of md5() in sysfunc(). Closes #239 2022-05-12 10:14:19 +00:00
Allan Bowe
d587b44b34 Merge pull request #238 from sasjs/allanbowe/mp-filtercheck-does-not-237
Updates to filtercheck macro (and tests)
2022-05-11 15:46:02 +03:00
munja
e43aac972a fix: coretable.sas 2022-05-11 13:41:34 +01:00
munja
7dbe31b5d3 fix: ensuring tests passing on sas 9 2022-05-11 13:32:27 +01:00
Allan Bowe
1672c96340 fix: testing fixes 2022-05-10 21:36:16 +00:00
Allan Bowe
453aee2c1f fix: update to mp_filtercheck & tests for special missings 2022-05-10 20:58:52 +00:00
Allan Bowe
00abbdcd65 fix: switching to proc datasets for ddl indexes 2022-05-10 20:58:35 +00:00
Allan Bowe
88685dc585 chore: providing description for DDL folder in main.dox 2022-05-10 19:19:53 +00:00
Allan Bowe
cf8147d6ca fix: making base_ds parameter positional in mp_ds2cards 2022-05-10 19:18:19 +00:00
Allan Bowe
f28f6b1530 Merge pull request #236 from sasjs/allanbowe/error-data-set-sashelp-235
fix: conditional logic for mp_getconstraints, test also updated.  Closes #235
2022-05-10 18:00:20 +03:00
Allan Bowe
cb4ea71e81 fix: conditional logic for mp_getconstraints, test also updated. Closes #235 2022-05-10 14:59:31 +00:00
Allan Bowe
fe94d3781a Merge pull request #234 from sasjs/all-contributors/add-eltociear
docs: add eltociear as a contributor for code
2022-05-10 13:54:01 +03:00
Allan Bowe
7c17b39dad Merge pull request #233 from eltociear/patch-1
chore: fix typo in mddl_sas_cntlout.sas
2022-05-10 13:53:26 +03:00
Allan Bowe
73dab4c651 chore: updating all.sas 2022-05-10 10:53:05 +00:00
allcontributors[bot]
5d72843167 docs: update .all-contributorsrc [skip ci] 2022-05-10 10:52:36 +00:00
allcontributors[bot]
f43df47cff docs: update README.md [skip ci] 2022-05-10 10:52:35 +00:00
Ikko Ashimine
aaca26770b chore: fix typo in mddl_sas_cntlout.sas
accomodate -> accommodate
2022-05-10 19:41:31 +09:00
Allan Bowe
4a124d5bd8 Update README.md 2022-05-09 09:58:31 +01:00
Allan Bowe
03cd52a01a chore: readme update and removal of main.dox in .npmignore (to allow doxygen folder descriptions in downstream apps) 2022-05-08 17:37:05 +00:00
Allan Bowe
da79181b00 Merge pull request #232 from sasjs/allanbowe/update-headers-in-sasjs-231
fix: using latest sasjs headers, closes #231
2022-05-08 01:27:02 +03:00
Allan Bowe
a405104052 fix: using latest sasjs headers, closes #231 2022-05-07 22:25:49 +00:00
Allan Bowe
56fdaa65d2 Merge pull request #230 from sasjs/dttmfix
feat: mf_dttm macro and associated test
2022-05-07 21:12:33 +03:00
Allan Bowe
9d60c49c9f chore: incorrect dependency 2022-05-07 18:04:28 +00:00
Allan Bowe
380170d5ba chore: all.sas 2022-05-07 18:02:16 +00:00
Allan Bowe
4b450f2091 fix: implementation of mf_fmtddtm() 2022-05-07 18:02:00 +00:00
Allan Bowe
1b013fbf1c fix: rename to mf_fmtdttm() 2022-05-07 17:49:06 +00:00
Allan Bowe
bf7459bd2d feat: mf_dttm macro and associated test 2022-05-07 17:45:36 +00:00
Allan Bowe
1096db0846 Merge pull request #229 from sasjs/runtimeissues
Improving WPS compatibility
2022-05-03 18:48:18 +03:00
Allan Bowe
fc9b765246 chore: updating all.sas 2022-05-03 15:46:34 +00:00
Allan Bowe
4a8f7bb014 fix: all the fixings 2022-05-03 15:46:15 +00:00
Allan Bowe
e0469be0d8 feat: updating mf_getvarcount to allow filtering by column type 2022-05-03 15:24:22 +00:00
Allan Bowe
e9e576b5ec fix: forcing misstype to NULL in ms_webout where not supported 2022-05-02 23:17:11 +00:00
138 changed files with 2747 additions and 1010 deletions

View File

@@ -126,6 +126,15 @@
"contributions": [
"code"
]
},
{
"login": "eltociear",
"name": "Ikko Ashimine",
"avatar_url": "https://avatars.githubusercontent.com/u/22633385?v=4",
"profile": "https://bandism.net/",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

8
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/javascript-node/.devcontainer/base.Dockerfile
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT="18-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
RUN apt-get update \
&& apt-get install -y doxygen

View File

@@ -0,0 +1,26 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/typescript-node
{
"name": "Node.js & TypeScript",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local on arm64/Apple Silicon.
"args": {
"VARIANT": "16-bullseye"
}
},
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"SASjs.sasjs-for-vscode"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm i && npm i -g @sasjs/cli",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
}

View File

@@ -6,7 +6,6 @@ sasjs/
.github/
.git-hooks/
.vscode/
main.dox
make_singlefile.sh
*.md
.all-contributorsrc

100
README.md
View File

@@ -18,7 +18,7 @@
[dependency-url]:https://github.com/sasjs/core/blob/main/package.json
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/CONTRIBUTING.md) are welcomed.
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.
You can download and compile them all in just two lines of SAS code:
@@ -31,14 +31,14 @@ Documentation: https://core.sasjs.io
## Components
### BASE library (All Platforms)
### BASE folder (All Platforms)
- OS independent
- Works on all SAS Platforms
- No X command
- Prefixes: _mf_, _mp_
### DDL library (All Platforms)
### DDL folder (All Platforms)
- OS independent
- Works on all SAS Platforms
@@ -47,46 +47,14 @@ Documentation: https://core.sasjs.io
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
### FCMP library (All Platforms)
### FCMP folder (All Platforms)
- Function and macro names are identical, except for special cases
- Prefixes: _mcf_
The fcmp macros are used to generate fcmp functions, and can be used with or without the `proc fcmp` wrapper.
### META library (SAS9 only)
Macros used in SAS EBI, which connect to the metadata server.
- OS independent
- Metadata aware
- No X command
- Prefixes: _mm_
### SERVER library (@sasjs/server only)
These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
- OS independent
- @sasjs/server aware
- No X command
- Prefixes: _ms_
### VIYA library (Viya only)
Macros used for interfacing with SAS Viya.
- OS independent
- No X command
- Prefixes: _mv_, _mvf_
### METAX library (SAS9 only)
- OS specific
- Metadata aware
- X command enabled
- Prefixes: _mmw_,_mmu_,_mmx_
### LUA library
### LUA folder
Wait - this is a macro library - what is LUA doing here? Well, it is a little known fact that you CAN run LUA within a SAS Macro. It has to be written to a text file with a `.lua` extension, from where you can `%include` it. So, without using the `proc lua` wrapper.
@@ -106,13 +74,61 @@ run;
- Prefixes: _ml_
### META folder (SAS9 only)
Macros used in SAS EBI, which connect to the metadata server.
- OS independent
- Metadata aware
- No X command
- Prefixes: _mm_
### METAX folder (SAS9 only)
- OS specific
- Metadata aware
- X command enabled
- Prefixes: _mmw_,_mmu_,_mmx_
### SERVER folder (@sasjs/server only)
These macros are used for building applications using [@sasjs/server](https://server.sasjs.io) - an open source REST API for Desktop SAS.
- OS independent
- @sasjs/server aware
- No X command
- Prefixes: _ms_
### VIYA folder (Viya only)
Macros used for interfacing with SAS Viya.
- OS independent
- No X command
- Prefixes: _mv_, _mvf_
### XPLATFORM folder (Viya, Meta, and Server)
Sometimes it is helpful to use a macro that can be used interchangeably regardless of the server type on which is is running (SASVIYA, SAS9, SASJS).
- OS independent
- No X command
- Prefixes: _mx_
## Installation
First, download the repo to a location your SAS system can access. Then update your sasautos path to include the components you wish to have available, eg:
```sas
options insert=(sasautos="/your/path/macrocore/base");
options insert=(sasautos="/your/path/macrocore/meta");
%let repoloc=/your/path/core;
options insert=(sasautos="&repoloc/base");
options insert=(sasautos="&repoloc/ddl");
options insert=(sasautos="&repoloc/fcmp");
options insert=(sasautos="&repoloc/lua");
options insert=(sasautos="&repoloc/meta");
options insert=(sasautos="&repoloc/metax");
options insert=(sasautos="&repoloc/server");
options insert=(sasautos="&repoloc/viya");
options insert=(sasautos="&repoloc/xplatform");
```
The above can be done directly in your sas program, via an autoexec, or an initialisation program.
@@ -142,7 +158,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
- _mp_ for macro procedures (which generate sas code)
- _ms_ for macro procedures that will only work with [@sasjs/server](https://github.com/sasjs/server)
- _mv_ for macro procedures that will only work in Viya
- _mx_ for macros that are XCMD enabled (working on both windows and unix)
- _mx_ for macros that work on Viya, SAS 9 EBI and SASjs Server
- follow verb-noun convention
- unix style line endings (lf)
- individual lines should be no more than 80 characters long
@@ -224,12 +240,13 @@ The following repositories are also worth checking out:
* [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros)
* [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs)
* [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros)
* [rogerjdeangelis](https://github.com/rogerjdeangelis)
* [scottbass/sas](https://github.com/scottbass/SAS)
* [yabwon/sas_packages](https://github.com/yabwon/SAS_PACKAGES)
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -251,6 +268,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
<td align="center"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
</tr>
</table>

1534
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,12 @@
%else %if "&SYSVLONG" < "9.04.01M3" %then 0;
%else 1;
%end;
%else %if &feature=EXPORTXLS %then %do;
/* is it possible to PROC EXPORT an excel file? */
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 1;
%else %if %sysfunc(sysprod(SAS/ACCESS Interface to PC Files)) = 1 %then 1;
%else 0;
%end;
%else %do;
-1
%put &sysmacroname: &feature not found;

42
base/mf_fmtdttm.sas Normal file
View File

@@ -0,0 +1,42 @@
/**
@file
@brief Returns E8601DT26.6 if compatible else DATETIME19.3
@details From our experience in [Data Controller for SAS]
(https://datacontroller.io) deployments, the E8601DT26.6 datetime format has
the widest support when it comes to pass-through SQL queries.
However, it is not supported in WPS or early versions of SAS 9 (M3 and below)
when used as a datetime literal, eg:
data _null_;
demo="%sysfunc(datetime(),E8601DT26.6)"dt;
demo=;
run;
This macro will therefore return DATEITME19.3 as an alternative format
based on the runtime environment so that it can be used in such cases, eg:
data _null_;
demo="%sysfunc(datetime(),%mf_fmtdttm())"dt;
demo=;
run;
<h4> Related Macros </h4>
@li mf_fmtdttm.test.sas
@author Allan Bowe
**/
%macro mf_fmtdttm(
)/*/STORE SOURCE*/;
%if "&sysver"="9.2" or "&sysver"="9.3"
or ("&sysver"="9.4" and "%substr(&SYSVLONG,9,1)" le "3")
or "%substr(&sysver,1,1)"="4"
or "%substr(&sysver,1,1)"="5"
%then %do;DATETIME19.3%end;
%else %do;E8601DT26.6%end;
%mend mf_fmtdttm;

View File

@@ -5,8 +5,12 @@
%put %mf_getplatform();
returns:
SASMETA (or SASVIYA)
returns one of:
@li SASMETA
@li SASVIYA
@li SASJS
@li BASESAS
@param switch the param for which to return a platform specific variable
@@ -68,4 +72,4 @@
%else %if &switch=VIYARESTAPI %then %do;
%mf_trimstr(%sysfunc(getoption(servicesbaseurl)),/)
%end;
%mend mf_getplatform;
%mend mf_getplatform;

View File

@@ -3,12 +3,12 @@
@brief Returns an unused libref
@details Use as follows:
libname mclib0 (work);
libname mclib1 (work);
libname mclib2 (work);
libname mclib0 (work);
libname mclib1 (work);
libname mclib2 (work);
%let libref=%mf_getuniquelibref();
%put &=libref;
%let libref=%mf_getuniquelibref();
%put &=libref;
which returns:

View File

@@ -2,31 +2,48 @@
@file
@brief Returns number of variables in a dataset
@details Useful to identify those renagade datasets that have no columns!
Can also be used to count for numeric, or character columns
%put Number of Variables=%mf_getvarcount(sashelp.class);
%put Number of Variables=%mf_getvarcount(sashelp.class);
%put Character Variables=%mf_getvarcount(sashelp.class,typefilter=C);
%put Numeric Variables = %mf_getvarcount(sashelp.class,typefilter=N);
returns:
> Number of Variables=4
@param libds Two part dataset (or view) reference.
@param [in] libds Two part dataset (or view) reference.
@param [in] typefilter= (A) Filter for certain types of column. Valid values:
@li A Count All columns
@li C Count Character columns only
@li N Count Numeric columns only
@version 9.2
@author Allan Bowe
**/
%macro mf_getvarcount(libds
%macro mf_getvarcount(libds,typefilter=A
)/*/STORE SOURCE*/;
%local dsid nvars rc ;
%local dsid nvars rc outcnt x;
%let dsid=%sysfunc(open(&libds));
%let nvars=.;
%let outcnt=0;
%let typefilter=%upcase(&typefilter);
%if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS));
%if &typefilter=A %then %let outcnt=&nvars;
%else %if &nvars>0 %then %do x=1 %to &nvars;
/* increment based on variable type */
%if %sysfunc(vartype(&dsid,&x))=&typefilter %then %do;
%let outcnt=%eval(&outcnt+1);
%end;
%end;
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put unable to open &libds (rc=&dsid);
%let rc=%sysfunc(close(&dsid));
%end;
&nvars
&outcnt
%mend mf_getvarcount;

View File

@@ -33,4 +33,4 @@
%if %sysfunc(findc(%str(&val),,kd)) %then %do;0%end;
%else %do;1%end;
%mend mf_isint;
%mend mf_isint;

View File

@@ -89,7 +89,12 @@
or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE
%then %do;
options obs=max replace nosyntaxcheck mprint;
options obs=max replace mprint;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
%then %do;
options nosyntaxcheck;
%end;
%if &mode=INCLUDE %then %do;
%if %sysfunc(exist(&errds))=1 %then %do;
data _null_;

View File

@@ -16,8 +16,11 @@
%mp_copyfolder(&rootdir,&copydir)
@param source Unquoted path to the folder to copy from.
@param target Unquoted path to the folder to copy to.
@param [in] source Unquoted path to the folder to copy from.
@param [out] target Unquoted path to the folder to copy to.
@param [in] copymax=(MAX) Set to a positive integer to indicate the level of
subdirectory copy recursion - eg 3, to go `./3/levels/deep`. For unlimited
recursion, set to MAX.
<h4> SAS Macros </h4>
@li mf_getuniquename.sas
@@ -31,7 +34,7 @@
**/
%macro mp_copyfolder(source,target);
%macro mp_copyfolder(source,target,copymax=MAX);
%mp_abort(iftrue=(%mf_isdir(&source)=0)
,mac=&sysmacroname
@@ -50,7 +53,7 @@
%let tempds=%mf_getuniquename();
/* recursive directory listing */
%mp_dirlist(path=&source,outds=work.&tempds, maxdepth=MAX)
%mp_dirlist(path=&source,outds=work.&tempds,maxdepth=&copymax)
/* create folders and copy content */
data _null_;
@@ -78,4 +81,4 @@
proc sql;
drop table work.&tempds;
%mend mp_copyfolder;
%mend mp_copyfolder;

View File

@@ -30,6 +30,7 @@
@li mddl_dc_filtersummary.sas
@li mddl_dc_locktable.sas
@li mddl_dc_maxkeytable.sas
@li mf_getuniquename.sas
<h4> Related Macros </h4>
@li mp_filterstore.sas
@@ -46,7 +47,7 @@
%macro mp_coretable(table_ref,libds=0
)/*/STORE SOURCE*/;
%local outds ;
%let outds=%sysfunc(ifc(&libds=0,_data_,&libds));
%let outds=%sysfunc(ifc(&libds=0,%mf_getuniquename(),&libds));
proc sql;
%if &table_ref=DIFFTABLE %then %do;
%mddl_dc_difftable(libds=&outds)
@@ -65,7 +66,8 @@ proc sql;
%end;
%if &libds=0 %then %do;
proc sql;
describe table &syslast;
drop table &syslast;
%end;
%mend mp_coretable;
%mend mp_coretable;

View File

@@ -1,50 +1,13 @@
/**
@file mp_createwebservice.sas
@brief Create a web service in SAS 9 or Viya
@details Creates a SASJS ready Stored Process in SAS 9 or Job Execution
Service in SAS Viya
@brief Create a web service in SAS 9, Viya or SASjs Server
@details This is actually a wrapper for mx_createwebservice.sas, remaining
for legacy purposes. For new apps, use mx_createwebservice.sas.
Usage:
%* compile macros ;
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* write some code;
filename ft15f001 temp;
parmcards4;
%* fetch any data from frontend ;
%webout(FETCH)
data example1 example2;
set sashelp.class;
run;
%* send data back;
%webout(OPEN)
%webout(ARR,example1) * Array format, fast, suitable for large tables ;
%webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE)
;;;;
%mp_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mm_createwebservice.sas
@li ms_createwebservice.sas
@li mv_createwebservice.sas
@li mx_createwebservice.sas
@param [in,out] path= The full folder path where the service will be created
@param [in,out] name= Service name. Avoid spaces.
@param [in] desc= The description of the service (optional)
@param [in] precode= Space separated list of filerefs, pointing to the code
that needs to be attached to the beginning of the service (optional)
@param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
be added
@param [in] replace= (YES) Select YES to replace any existing service in that
location
@param [in] mDebug= (0) set to 1 to show debug messages in the log
@version 9.2
@author Allan Bowe
**/
@@ -57,40 +20,13 @@ Usage:
,mdebug=0
)/*/STORE SOURCE*/;
%if &syscc ge 4 %then %do;
%put syscc=&syscc - &sysmacroname will not execute in this state;
%return;
%end;
%local platform; %let platform=%mf_getplatform();
%if &platform=SASVIYA %then %do;
%if "&path"="HOME" %then %let path=/Users/&sysuserid/My Folder;
%mv_createwebservice(path=&path
%mx_createwebservice(path=&path
,name=&name
,code=&code
,precode=&precode
,code=&code
,desc=&desc
,replace=&replace
)
%end;
%else %if &platform=SASJS %then %do;
%if "&path"="HOME" %then %let path=/Users/&_sasjs_username/My Folder;
%ms_createwebservice(path=&path
,name=&name
,code=&code
,precode=&precode
,mdebug=&mdebug
)
%end;
%else %do;
%if "&path"="HOME" %then %let path=/User Folders/&_METAPERSON/My Folder;
%mm_createwebservice(path=&path
,name=&name
,code=&code
,precode=&precode
,desc=&desc
,replace=&replace
)
%end;
%mend mp_createwebservice;

View File

@@ -11,7 +11,7 @@
Usage:
%mp_ds2cards(base_ds=sashelp.class
%mp_ds2cards(sashelp.class
, tgt_ds=work.class
, cards_file= "C:\temp\class.sas"
, showlog=NO
@@ -23,7 +23,7 @@
- explicity setting a unix LF
- constraints / indexes etc
@param [in] base_ds= Should be two level - eg work.blah. This is the table
@param [in] base_ds Should be two level - eg work.blah. This is the table
that is converted to a cards file.
@param [in] tgt_ds= Table that the generated cards file would create.
Optional - if omitted, will be same as BASE_DS.

View File

@@ -57,6 +57,11 @@
%local vars;
%let vars=%upcase(%mf_getvarlist(&libds));
%if %trim(X&vars)=X %then %do;
%put &sysmacroname: Table &libds has no columns!!;
%return;
%end;
/* create the header row */
data _null_;
file &outref;

View File

@@ -92,7 +92,36 @@ data &outds;
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
OPERATOR_NM $10 RAW_VALUE $4000;*/
set &inds;
length reason_cd $4032;
length reason_cd $4032 vtype $1 vnum dsid 8;
/* quick check to ensure column exists */
if upcase(VARIABLE_NM) not in
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
then do;
REASON_CD="Variable "!!cats(variable_nm)!!" not in &targetds";
putlog REASON_CD= VARIABLE_NM=;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
return;
end;
/* need to open the dataset to get the column type */
dsid=open("&targetds","i");
if dsid>0 then do;
vnum=varnum(dsid,VARIABLE_NM);
if vnum<1 then do;
/* should not happen as was also tested for above */
REASON_CD=cats("Variable (",VARIABLE_NM,") not found in &targetds");
putlog REASON_CD= dsid=;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
return;
end;
/* now we can get the type */
else vtype=vartype(dsid,vnum);
end;
/* closed list checks */
if GROUP_LOGIC not in ('AND','OR') then do;
@@ -116,17 +145,8 @@ data &outds;
call symputx('nobs',_n_,'l');
output;
end;
if upcase(VARIABLE_NM) not in
(%upcase(%mf_getvarlist(&targetds,dlm=%str(,),quote=SINGLE)))
then do;
REASON_CD="Variable "!!cats(variable_nm)!!" not in &targetds";
putlog REASON_CD= VARIABLE_NM=;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
end;
if OPERATOR_NM not in
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS','GE','LE')
('=','>','<','<=','>=','NE','GE','LE','BETWEEN','IN','NOT IN','CONTAINS')
then do;
REASON_CD='Invalid OPERATOR_NM: '!!cats(OPERATOR_NM);
putlog REASON_CD= OPERATOR_NM=;
@@ -135,6 +155,18 @@ data &outds;
output;
end;
/* special missing logic */
if vtype='N'
and OPERATOR_NM in ('=','>','<','<=','>=','NE','GE','LE')
and cats(upcase(raw_value)) in (
'.','.A','.B','.C','.D','.E','.F','.G','.H','.I','.J','.K','.L','.M','.N'
'.N','.O','.P','.Q','.R','.S','.T','.U','.V','.W','.X','.Y','.Z','._'
)
then do;
/* valid numeric - exit data step loop */
return;
end;
/* special logic */
if OPERATOR_NM='BETWEEN' then raw_value1=tranwrd(raw_value,' AND ','');
else if OPERATOR_NM in ('IN','NOT IN') then do;

View File

@@ -84,6 +84,9 @@ filename &outref temp;
run;
%end;
%else %do;
proc sort data=&inds;
by SUBGROUP_ID;
run;
data _null_;
file &outref lrecl=32800;
set &inds end=last;

View File

@@ -40,6 +40,22 @@
%let lib=%upcase(&lib);
%let ds=%upcase(&ds);
/**
* Cater for environments where sashelp.vcncolu is not available
*/
%if %sysfunc(exist(sashelp.vcncolu,view))=0 %then %do;
proc sql;
create table &outds(
libref char(8)
,TABLE_NAME char(32)
,constraint_type char(8) label='Constraint Type'
,constraint_name char(32) label='Constraint Name'
,column_name char(32) label='Column'
,constraint_order num
);
%return;
%end;
/**
* Neither dictionary tables nor sashelp provides a constraint order column,
* however they DO arrive in the correct order. So, create the col.

View File

@@ -41,6 +41,7 @@
<h4> SAS Macros </h4>
@li mcf_length.sas
@li mf_getuniquename.sas
@li mf_getvarcount.sas
@li mf_getvarlist.sas
@li mf_getvartype.sas
@li mf_getvarformat.sas
@@ -60,7 +61,7 @@
,outds=work.mp_getmaxvarlengths
)/*/STORE SOURCE*/;
%local vars prefix x var fmt;
%local vars prefix x var fmt srcds;
%let vars=%mf_getvarlist(libds=&libds);
%let prefix=%substr(%mf_getuniquename(),1,25);
%let num2char=%upcase(&num2char);
@@ -70,6 +71,24 @@
%mcf_length(wrap=YES, insert_cmplib=YES)
%end;
%if &num2char=NO
and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5")
and %mf_getvarcount(&libds,typefilter=N) gt 0
%then %do;
/* custom functions not supported in summary operations */
%let srcds=%mf_getuniquename();
data &srcds/view=&srcds;
set &libds;
%do x=1 %to %sysfunc(countw(&vars,%str( )));
%let var=%scan(&vars,&x);
%if %mf_getvartype(&libds,&var)=N %then %do;
&prefix.&x=mcf_length(&var);
%end;
%end;
run;
%end;
%else %let srcds=&libds;
proc sql;
create table &outds (rename=(
%do x=1 %to %sysfunc(countw(&vars,%str( )));
@@ -94,10 +113,15 @@ create table &outds (rename=(
%end;
%end;
%else %do;
max(mcf_length(&var)) as &prefix.&x
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
max(&prefix.&x) as &prefix.&x
%end;
%else %do;
max(mcf_length(&var)) as &prefix.&x
%end;
%end;
%end;
from &libds;
from &srcds;
proc transpose data=&outds
out=&outds(rename=(_name_=NAME COL1=MAXLEN));

View File

@@ -58,7 +58,7 @@
%if %mf_getattrn(&libds,NLOBS)=0 %then %do;
data &outds;
length hashkey $32;
retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)";
hashkey=put(md5("&salt"),$hex32.);
output;
stop;
run;
@@ -69,9 +69,14 @@
%put %str(ERR)OR: Dataset &libds is not a dataset;
%end;
%else %do;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar)
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
/nonote2err
%end;
;
length &prevkeyvar &keyvar $32;
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
retain &prevkeyvar;
if _n_=1 then &prevkeyvar=put(md5("&salt"),$hex32.);
set &libds end=&lastvar;
/* hash should include previous row */
&keyvar=%mp_md5(

View File

@@ -22,6 +22,7 @@
@param [in] loop_secs= (1) Seconds to wait between each lock attempt
<h4> SAS Macros </h4>
@li mf_fmtdttm.sas
@li mp_abort.sas
@li mp_lockfilecheck.sas
@li mf_getuser.sas
@@ -111,7 +112,7 @@ run;
LOCK_LIB ="&lib";
LOCK_DS="&ds";
LOCK_STATUS_CD='LOCKED';
LOCK_START_DTTM="%sysfunc(datetime(),E8601DT26.6)"dt;
LOCK_START_DTTM="%sysfunc(datetime(),%mf_fmtdttm())"dt;
LOCK_USER_NM="&user";
LOCK_PID="&sysjobid";
LOCK_REF="&ref";
@@ -131,7 +132,7 @@ run;
proc sql;
update &ctl_ds
set LOCK_STATUS_CD='LOCKED'
, LOCK_START_DTTM="%sysfunc(datetime(),E8601DT26.6)"dt
, LOCK_START_DTTM="%sysfunc(datetime(),%mf_fmtdttm())"dt
, LOCK_USER_NM="&user"
, LOCK_PID="&sysjobid"
, LOCK_REF="&ref"
@@ -206,7 +207,7 @@ run;
proc sql;
update &ctl_ds
set LOCK_STATUS_CD='UNLOCKED'
, LOCK_END_DTTM="%sysfunc(datetime(),E8601DT26.6)"dt
, LOCK_END_DTTM="%sysfunc(datetime(),%mf_fmtdttm())"dt
, LOCK_USER_NM="&user"
, LOCK_PID="&sysjobid"
, LOCK_REF="&ref"

View File

@@ -21,15 +21,19 @@ https://blogs.sas.com/content/sastraining/2012/08/14/jedi-sas-tricks-reset-sas-s
%macro mp_resetoption(option /* the option to reset */
)/*/STORE SOURCE*/;
data _null_;
length code $1500;
startup=getoption("&option",'startupvalue');
current=getoption("&option");
if startup ne current then do;
code =cat('OPTIONS ',getoption("&option",'keyword','startupvalue'),';');
putlog "NOTE: Resetting system option: " code ;
call execute(code );
end;
run;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
data _null_;
length code $1500;
startup=getoption("&option",'startupvalue');
current=getoption("&option");
if startup ne current then do;
code =cat('OPTIONS ',getoption("&option",'keyword','startupvalue'),';');
putlog "NOTE: Resetting system option: " code ;
call execute(code );
end;
run;
%end;
%else %do;
%put &sysmacroname: reset option feature unavailable on &sysvlong;
%end;
%mend mp_resetoption;

View File

@@ -58,6 +58,7 @@
<h4> SAS Macros </h4>
@li mf_existvar.sas
@li mf_fmtdttm.sas
@li mf_getquotedstr.sas
@li mf_getuniquename.sas
@li mf_nobs.sas
@@ -217,12 +218,12 @@ quit;
set keytable="&base_libds"
,keycolumn="&retained_key"
,max_key=%eval(&maxkey+&newkey_cnt)
,processed_dttm="%sysfunc(datetime(),E8601DT26.6)"dt;
,processed_dttm="%sysfunc(datetime(),%mf_fmtdttm())"dt;
%end;
%else %do;
update &maxkeytable
set max_key=%eval(&maxkey+&newkey_cnt)
,processed_dttm="%sysfunc(datetime(),E8601DT26.6)"dt
,processed_dttm="%sysfunc(datetime(),%mf_fmtdttm())"dt
where keytable="&base_libds";
%end;
%mp_lockanytable(UNLOCK

View File

@@ -125,7 +125,7 @@
data &ds1;
set &dslist indsname=&inds_auto;
&hashkey=put(md5(catx('|',%mf_getquotedstr(&key,quote=N))),$hex32.);
&inds_keep=&inds_auto;
&inds_keep=upcase(&inds_auto);
proc sort;
by &inds_keep &hashkey;
run;
@@ -160,8 +160,8 @@ data &ds4;
tgtvar_nm=upcase(tgtvar_nm);
if tgtvar_nm in (%upcase(&vlist));
if &inds_auto="&ds2" then tgtvar_type='N';
else if &inds_auto="&ds3" then tgtvar_type='C';
if upcase(&inds_auto)="&ds2" then tgtvar_type='N';
else if upcase(&inds_auto)="&ds3" then tgtvar_type='C';
else do;
putlog "%str(ERR)OR: unidentified vartype input!" &inds_auto;
call symputx('syscc',98);

View File

@@ -1,53 +1,11 @@
/**
@file
@brief Will execute a SASjs web service on SAS 9 or Viya
@details Prepares the input files and retrieves the resulting datasets from
the response JSON.
Note - the _webout fileref should NOT be assigned prior to running this macro.
@param [in] program The _PROGRAM endpoint to test
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
follows:
inputfiles=inref:filename inref2:filename2
@param [in] inputdatasets= (0) All datasets in this space seperated list are
converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to
the list of `inputfiles` for ingestion. The dataset will be sent with the
same name (no need for a colon modifier).
@param [in] inputparams=(0) A dataset containing name/value pairs in the
following format:
|name:$32|value:$1000|
|---|---|
|stpmacname|some value|
|mustbevalidname|can be anything, oops, %abort!!|
@param [in] debug= (log) Provide the _debug value
@param [in] mdebug= (0) Set to 1 to provide macro debugging
@param [in] viyaresult= (WEBOUT_JSON) The Viya result type to return. For
more info, see mv_getjobresult.sas
@param [in] viyacontext= (SAS Job Execution compute context) The Viya compute
context on which to run the service
@param [out] outlib= (0) Output libref to contain the final tables. Set to
0 if the service output is not in JSON format.
@param [out] outref= (0) Output fileref to create, to contain the full _webout
response.
@brief To be deprecated. Will execute a SASjs web service on SAS 9 or Viya
@details Use the mx_testservice.sas macro instead (documentation can be
found there)
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mp_chop.sas
@li mp_ds2csv.sas
@li ms_testservice.sas
@li mv_getjobresult.sas
@li mv_jobflow.sas
<h4> Related Programs </h4>
@li mp_testservice.test.sas
@li mx_testservice.sas
@version 9.4
@author Allan Bowe
@@ -65,237 +23,17 @@
viyaresult=WEBOUT_JSON,
viyacontext=SAS Job Execution compute context
)/*/STORE SOURCE*/;
%local dbg pcnt fref1 fref2 webref webrefpath i webcount var platform;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
/* sanitise inputparams */
%let pcnt=0;
%if &inputparams ne 0 %then %do;
data _null_;
set &inputparams;
if not nvalid(name,'v7') then putlog (_all_)(=);
else if name in (
'program','inputfiles','inputparams','debug','outlib','outref'
) then putlog (_all_)(=);
else do;
x+1;
call symputx(name,quote(cats(value)),'l');
call symputx(cats('pval',x),name,'l');
call symputx('pcnt',x,'l');
end;
run;
%mp_abort(iftrue= (%mf_nobs(&inputparams) ne &pcnt)
,mac=&sysmacroname
,msg=%str(Invalid values in &inputparams)
)
%end;
%mx_testservice(&program,
inputfiles=&inputfiles,
inputdatasets=&inputdatasets,
inputparams=&inputparams,
debug=&debug,
mdebug=&mdebug,
outlib=&outlib,
outref=&outref,
viyaresult=&viyaresult,
viyacontext=&viyacontext
)
/* convert inputdatasets to filerefs */
%if "&inputdatasets" ne "0" %then %do;
%if %quote(&inputfiles)=0 %then %let inputfiles=;
%do i=1 %to %sysfunc(countw(&inputdatasets,%str( )));
%let var=%scan(&inputdatasets,&i,%str( ));
%local dsref&i;
%let dsref&i=%mf_getuniquefileref();
%mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS)
%let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.);
%end;
%end;
%let platform=%mf_getplatform();
%let fref1=%mf_getuniquefileref();
%let fref2=%mf_getuniquefileref();
%let webref=%mf_getuniquefileref();
%let webrefpath=%sysfunc(pathname(work))/%mf_getuniquename();
/* mp_chop requires a physical path as input */
filename &webref "&webrefpath";
%if &platform=SASMETA %then %do;
/* parse the input files */
%if %quote(&inputfiles) ne 0 %then %do;
%let webcount=%sysfunc(countw(&inputfiles));
%put &=webcount;
%do i=1 %to &webcount;
%let var=%scan(&inputfiles,&i,%str( ));
%local webfref&i webname&i;
%let webref&i=%scan(&var,1,%str(:));
%let webname&i=%scan(&var,2,%str(:));
%put webref&i=&&webref&i;
%put webname&i=&&webname&i;
%end;
%end;
%else %let webcount=0;
proc stp program="&program";
inputparam _program="&program"
%do i=1 %to &webcount;
%if &webcount=1 %then %do;
_webin_fileref="&&webref&i"
_webin_name="&&webname&i"
%end;
%else %do;
_webin_fileref&i="&&webref&i"
_webin_name&i="&&webname&i"
%end;
%end;
_webin_file_count="&webcount"
_debug="&debug"
%do i=1 %to &pcnt;
/* resolve name only, proc stp fetches value */
&&pval&i=&&&&&&pval&i
%end;
;
%do i=1 %to &webcount;
inputfile &&webref&i;
%end;
outputfile _webout=&webref;
run;
data _null_;
infile &webref;
file &fref1;
input;
length line $10000;
if index(_infile_,'>>weboutBEGIN<<') then do;
line=tranwrd(_infile_,'>>weboutBEGIN<<','');
put line;
end;
else if index(_infile_,'>>weboutEND<<') then do;
line=tranwrd(_infile_,'>>weboutEND<<','');
put line;
stop;
end;
else put _infile_;
run;
data _null_;
infile &fref1;
input;
put _infile_;
run;
%if &outlib ne 0 %then %do;
libname &outlib json (&fref1);
%end;
%if &outref ne 0 %then %do;
filename &outref temp;
%mp_binarycopy(inref=&webref,outref=&outref)
%end;
%end;
%else %if &platform=SASVIYA %then %do;
/* prepare inputparams */
%local ds1;
%let ds1=%mf_getuniquename();
%if "&inputparams" ne "0" %then %do;
proc transpose data=&inputparams out=&ds1;
id name;
var value;
run;
%end;
%else %do;
data &ds1;run;
%end;
/* parse the input files - convert to sasjs params */
%local webcount i var sasjs_tables;
%if %quote(&inputfiles) ne 0 %then %do;
%let webcount=%sysfunc(countw(&inputfiles));
%put &=webcount;
%do i=1 %to &webcount;
%let var=%scan(&inputfiles,&i,%str( ));
%local webfref&i webname&i sasjs&i.data;
%let webref&i=%scan(&var,1,%str(:));
%let webname&i=%scan(&var,2,%str(:));
%put webref&i=&&webref&i;
%put webname&i=&&webname&i;
%let sasjs_tables=&sasjs_tables &&webname&i;
data _null_;
infile &&webref&i lrecl=32767;
input;
if _n_=1 then call symputx("sasjs&i.data",_infile_);
else call symputx(
"sasjs&i.data",cats(symget("sasjs&i.data"),'0D0A'x,_infile_)
);
putlog "&sysmacroname infile: " _infile_;
run;
data &ds1;
set &ds1;
length sasjs&i.data $32767 sasjs_tables $1000;
sasjs&i.data=symget("sasjs&i.data");
sasjs_tables=symget("sasjs_tables");
run;
%end;
%end;
%else %let webcount=0;
data &ds1;
retain _program "&program";
retain _contextname "&viyacontext";
set &ds1;
putlog "&sysmacroname inputparams:";
putlog (_all_)(=);
run;
%mv_jobflow(inds=&ds1
,maxconcurrency=1
,outds=work.results
,outref=&fref1
,mdebug=&mdebug
)
/* show the log */
data _null_;
infile &fref1;
input;
putlog _infile_;
run;
/* get the uri to fetch results */
data _null_;
set work.results;
call symputx('uri',uri);
putlog "&sysmacroname: fetching results for " uri;
run;
/* fetch results from webout.json */
%mv_getjobresult(uri=&uri,
result=&viyaresult,
outref=&outref,
outlib=&outlib,
mdebug=&mdebug
)
%end;
%else %if &platform=SASJS %then %do;
%ms_testservice(&program
,inputfiles=&inputfiles
,inputdatasets=&inputdatasets
,inputparams=&inputparams
,debug=&debug
,mdebug=&mdebug
,outlib=&outlib
,outref=&outref
)
%end;
%else %do;
%put %str(ERR)OR: Unrecognised platform: &platform;
%end;
%if &mdebug=0 %then %do;
filename &fref1 clear;
%if &platform ne SASJS %then %do;
filename &fref2 clear;
filename &webref clear;
%end;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend mp_testservice;
%mend mp_testservice;

View File

@@ -102,7 +102,7 @@ options noquotelenmax;
"""
f = open('all.sas', "w") # r / r+ / rb / rb+ / w / wb
f.write(header)
folders = ['base', 'ddl', 'meta', 'metax', 'server', 'viya', 'lua', 'fcmp']
folders = ['base', 'ddl', 'meta', 'metax', 'server', 'viya', 'lua', 'fcmp', 'xplatform']
for folder in folders:
filenames = [fn for fn in Path(
'./' + folder).iterdir() if fn.match("*.sas")]

View File

@@ -26,9 +26,19 @@
oldval_num num format=best32. label='Old (numeric) value',
newval_num num format=best32. label='New (numeric) value',
oldval_char char(32765) label='Old (character) value',
newval_char char(32765) label='New (character) value',
constraint pk_mpe_audit
primary key(load_ref,libref,dsn,key_hash,tgtvar_nm)
newval_char char(32765) label='New (character) value'
);
%local lib;
%let libds=%upcase(&libds);
%if %index(&libds,.)=0 %then %let lib=WORK;
%else %let lib=%scan(&libds,1,.);
proc datasets lib=&lib noprint;
modify %scan(&libds,-1,.);
index create
pk_mpe_audit=(load_ref libref dsn key_hash tgtvar_nm)
/nomiss unique;
quit;
%mend mddl_dc_difftable;

View File

@@ -9,19 +9,32 @@
%macro mddl_dc_filterdetail(libds=WORK.FILTER_DETAIL);
%local nn lib;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
%let nn=not null;
%end;
%else %let nn=;
proc sql;
create table &libds(
filter_hash char(32) not null,
filter_line num not null,
group_logic char(3) not null,
subgroup_logic char(3) not null,
subgroup_id num not null,
variable_nm varchar(32) not null,
operator_nm varchar(12) not null,
raw_value varchar(4000) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_hash,filter_line)
filter_hash char(32) &nn,
filter_line num &nn,
group_logic char(3) &nn,
subgroup_logic char(3) &nn,
subgroup_id num &nn,
variable_nm varchar(32) &nn,
operator_nm varchar(12) &nn,
raw_value varchar(4000) &nn,
processed_dttm num &nn format=E8601DT26.6
);
%let libds=%upcase(&libds);
%if %index(&libds,.)=0 %then %let lib=WORK;
%else %let lib=%scan(&libds,1,.);
proc datasets lib=&lib noprint;
modify %scan(&libds,-1,.);
index create pk_mpe_filterdetail=(filter_hash filter_line)/nomiss unique;
quit;
%mend mddl_dc_filterdetail;

View File

@@ -9,14 +9,27 @@
%macro mddl_dc_filtersummary(libds=WORK.FILTER_SUMMARY);
%local nn lib;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
%let nn=not null;
%end;
%else %let nn=;
proc sql;
create table &libds(
filter_rk num not null,
filter_hash char(32) not null,
filter_table char(41) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_rk)
filter_rk num &nn,
filter_hash char(32) &nn,
filter_table char(41) &nn,
processed_dttm num &nn format=E8601DT26.6
);
%let libds=%upcase(&libds);
%if %index(&libds,.)=0 %then %let lib=WORK;
%else %let lib=%scan(&libds,1,.);
proc datasets lib=&lib noprint;
modify %scan(&libds,-1,.);
index create filter_rk /nomiss unique;
quit;
%mend mddl_dc_filtersummary;

View File

@@ -9,17 +9,33 @@
%macro mddl_dc_locktable(libds=WORK.LOCKTABLE);
%local nn lib;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
%let nn=not null;
%end;
%else %let nn=;
proc sql;
create table &libds(
lock_lib char(8),
lock_ds char(32),
lock_status_cd char(10) not null,
lock_user_nm char(100) not null ,
lock_status_cd char(10) &nn,
lock_user_nm char(100) &nn ,
lock_ref char(200),
lock_pid char(10),
lock_start_dttm num format=E8601DT26.6,
lock_end_dttm num format=E8601DT26.6,
constraint pk_mp_lockanytable primary key(lock_lib,lock_ds)
lock_end_dttm num format=E8601DT26.6
);
%let libds=%upcase(&libds);
%if %index(&libds,.)=0 %then %let lib=WORK;
%else %let lib=%scan(&libds,1,.);
proc datasets lib=&lib noprint;
modify %scan(&libds,-1,.);
index create
pk_mp_lockanytable=(lock_lib lock_ds)
/nomiss unique;
quit;
%mend mddl_dc_locktable;

View File

@@ -17,8 +17,17 @@
max_key num label=
'Integer representing current max RK or SK value in the KEYTABLE',
processed_dttm num format=E8601DT26.6
label='Datetime this value was last updated',
constraint pk_mpe_maxkeyvalues
primary key(keytable));
label='Datetime this value was last updated'
);
%local lib;
%let libds=%upcase(&libds);
%if %index(&libds,.)=0 %then %let lib=WORK;
%else %let lib=%scan(&libds,1,.);
proc datasets lib=&lib noprint;
modify %scan(&libds,-1,.);
index create keytable /nomiss unique;
quit;
%mend mddl_dc_maxkeytable;

View File

@@ -14,8 +14,8 @@ proc sql;
create table &libds(
FMTNAME char(32) label='Format name'
/*
to accomodate larger START values, mp_loadformat.sas will need the
SQL dependency removed (proc sql needs to accomodate 3 index values in
to accommodate larger START values, mp_loadformat.sas will need the
SQL dependency removed (proc sql needs to accommodate 3 index values in
a 32767 ibufsize limit)
*/
,START char(10000) label='Starting value for format'
@@ -40,4 +40,4 @@ create table &libds(
,LANGUAGE char(8) label='Language for date strings'
);
%mend mddl_sas_cntlout;
%mend mddl_sas_cntlout;

View File

@@ -92,4 +92,26 @@
* Auto-generated from the plain source `.lua` files in the same directory
* Prefixes: _ml_
*/
*/
/*! \dir ddl
* \brief Data Definition Language files
* \details Provides templates for commonly used tables in sasjs/core.
Attributes:
* OS independent
* No X command
* Prefixes: _mddl_
*/
/*! \dir xplatform
* \brief Cross Platform, works on all SAS servers (Viya, EBI, SASjs)
* \details Useful when you need to run a single piece of code against Viya,
SAS 9 with metadata, or SASjs on Base SAS.
* OS independent
* No X command
* Prefixes: _mx_
*/

View File

@@ -6,8 +6,10 @@
"fcmp",
"lua",
"server",
"tests/crossplatform",
"tests/ddl"
"xplatform",
"tests/base",
"tests/ddl",
"tests/xplatform"
],
"docConfig": {
"displayMacroCore": false,
@@ -43,7 +45,7 @@
},
{
"name": "sas9",
"serverUrl": "https://sas.analytium.co.uk:8343",
"serverUrl": "",
"serverType": "SAS9",
"httpsAgentOptions": {
"allowInsecureRequests": false
@@ -78,7 +80,7 @@
},
{
"name": "docsonly",
"serverType": "SAS9",
"serverType": "SASJS",
"appLoc": "dummy",
"macroFolders": [
"meta",
@@ -105,4 +107,4 @@
"contextName": "SAS Job Execution compute context"
}
]
}
}

View File

@@ -68,8 +68,8 @@ data _null_;
file &fname1 lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put "Content-Type: multipart/form-data; boundary=&boundary";
put "Authorization: Bearer " _infile_;
if _n_=1 then put "Content-Type: multipart/form-data; boundary=&boundary";
put _infile_;
run;
%if &mdebug=1 %then %do;

149
server/ms_creategroup.sas Normal file
View File

@@ -0,0 +1,149 @@
/**
@file
@brief Creates a group on SASjs Server
@details Creates a group on SASjs Server with the following attributes:
@li name
@li description
@li isActive
Examples:
%ms_creategroup(mynewgroup)
%ms_creategroup(mynewergroup, desc=The group description)
@param [in] groupname The group name to create. No spaces or special chars.
@param [in] desc= (0) If no description provided, group name will be used.
@param [in] isactive= (true) Set to false to create an inactive group.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [out] outds= (work.ms_creategroup) This output dataset will contain the
values from the JSON response (such as the id of the new group)
|DESCRIPTION:$1.|GROUPID:best.|ISACTIVE:best.|NAME:$11.|
|---|---|---|---|
|`The group description`|`2 `|`1 `|`mynewergroup `|
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mp_abort.sas
<h4> Related Files </h4>
@li ms_creategroup.test.sas
@li ms_getgroups.sas
**/
%macro ms_creategroup(groupname
,desc=0
,isactive=true
,outds=work.ms_creategroup
,mdebug=0
);
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_creategroup.sas
,msg=%str(syscc=&syscc on macro entry)
)
%local fref0 fref1 fref2 libref optval rc msg;
%let fref0=%mf_getuniquefileref();
%let fref1=%mf_getuniquefileref();
%let fref2=%mf_getuniquefileref();
%let libref=%mf_getuniquelibref();
/* avoid sending bom marker to API */
%let optval=%sysfunc(getoption(bomfile));
options nobomfile;
data _null_;
file &fref0 termstr=crlf;
name=quote(cats(symget('groupname')));
description=quote(cats(symget('desc')));
if cats(description)='"0"' then description=name;
isactive=symget('isactive');
%if &mdebug=1 %then %do;
putlog _all_;
%end;
put '{'@;
put '"name":' name @;
put ',"description":' description @;
put ',"isActive":' isactive @;
put '}';
run;
data _null_;
file &fref1 lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
if _n_=1 then do;
put "Content-Type: application/json";
put "accept: application/json";
end;
put _infile_;
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fref0;
input;
put _infile_;
data _null_;
infile &fref1;
input;
put _infile_;
run;
%end;
proc http method='POST' in=&fref0 headerin=&fref1 out=&fref2
url="&_sasjs_apiserverurl/SASjsApi/group";
%if &mdebug=1 %then %do;
debug level=1;
%end;
run;
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_creategroup.sas
,msg=%str(Issue submitting query to SASjsApi/group)
)
libname &libref JSON fileref=&fref2;
data &outds;
set &libref..root;
drop ordinal_root;
%if &mdebug=1 %then %do;
putlog _all_;
%end;
run;
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_creategroup.sas
,msg=%str(Issue reading response JSON)
)
/* reset options */
options &optval;
%if &mdebug=0 %then %do;
filename &fref0 clear;
filename &fref1 clear;
filename &fref2 clear;
libname &libref clear;
%end;
%else %do;
data _null_;
infile &fref2;
input;
putlog _infile_;
run;
%end;
%mend ms_creategroup;

View File

@@ -87,9 +87,11 @@ data _null_;
file &fref1 lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put "Authorization: Bearer " _infile_;
put "Content-Type: application/json";
put "accept: application/json";
if _n_=1 then do;
put "Content-Type: application/json";
put "accept: application/json";
end;
put _infile_;
run;
%if &mdebug=1 %then %do;

View File

@@ -390,6 +390,11 @@ data _null_;
put '%end; ';
put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do; ';
put ' /* functions in formats unsupported */ ';
put ' %put &sysmacroname: forcing missing back to NULL as feature not supported; ';
put ' %let missing=NULL; ';
put ' %end; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
put ' ) ';

View File

@@ -33,7 +33,7 @@ data _null_;
file &headref lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put "Authorization: Bearer " _infile_;
put _infile_;
run;
proc http method='DELETE' headerin=&headref

View File

@@ -34,7 +34,7 @@ data _null_;
file &headref lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put "Authorization: Bearer " _infile_;
put _infile_;
run;
proc http method='GET' out=&binaryfref headerin=&headref

105
server/ms_getgroups.sas Normal file
View File

@@ -0,0 +1,105 @@
/**
@file
@brief Fetches the list of groups from SASjs Server
@details Fetches the list of groups from SASjs Server and writes them to an
output dataset.
Example:
%ms_getgroups(outds=userlist)
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
list of groups. Format:
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|---|---|---|
|`SomeGroup `|`A group `|`1`|
|`Another Group`|`this is a different group`|`2`|
|`admin`|`Administrators `|`3`|
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mp_abort.sas
<h4> Related Files </h4>
@li ms_creategroup.sas
@li ms_getusers.test.sas
**/
%macro ms_getgroups(
outds=work.ms_getgroups
,mdebug=0
);
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_getusers.sas
,msg=%str(syscc=&syscc on macro entry)
)
%local fref0 fref1 libref optval rc msg;
%let fref0=%mf_getuniquefileref();
%let fref1=%mf_getuniquefileref();
%let libref=%mf_getuniquelibref();
/* avoid sending bom marker to API */
%let optval=%sysfunc(getoption(bomfile));
options nobomfile;
data _null_;
file &fref0 lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
if _n_=1 then put "accept: application/json";
put _infile_;
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fref0;
input;
put _infile_;
run;
%end;
proc http method='GET' headerin=&fref0 out=&fref1
url="&_sasjs_apiserverurl/SASjsApi/group";
%if &mdebug=1 %then %do;
debug level=1;
%end;
run;
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_getgroups.sas
,msg=%str(Issue submitting GET query to SASjsApi/group)
)
libname &libref JSON fileref=&fref1;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..root;
drop ordinal_root;
run;
%mp_abort(
iftrue=(&syscc ne 0)
,mac=ms_getusers.sas
,msg=%str(Issue reading response JSON)
)
/* reset options */
options &optval;
%if &mdebug=1 %then %do;
filename &fref0 clear;
filename &fref1 clear;
libname &libref clear;
%end;
%mend ms_getgroups;

View File

@@ -56,8 +56,8 @@ data _null_;
file &fref0 lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put "Authorization: Bearer " _infile_;
put "accept: application/json";
if _n_=1 then put "accept: application/json";
put _infile_;
run;
%if &mdebug=1 %then %do;

View File

@@ -137,8 +137,8 @@ data _null_;
file &authref lrecl=1000;
infile "&_sasjs_tokenfile" lrecl=1000;
input;
put 'Authorization: Bearer ' _infile_;
put "Content-Type: multipart/form-data; boundary=&boundary";
if _n_=1 then put "Content-Type: multipart/form-data; boundary=&boundary";
put _infile_;
run;
%if &mdebug=1 %then %do;
@@ -162,6 +162,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
data _null_;infile &outref;input;putlog _infile_;run;
%end;
@@ -177,7 +178,7 @@ options &optval;
%if &outlogds ne _null_ or &mdebug=1 %then %do;
%local dumplib;
%let dumplib=%mf_getuniquelibref();
libname &dumplib json (&outref);
libname &dumplib json fileref=&outref;
data &outlogds;
set &dumplib..log;
%if &mdebug=1 %then %do;
@@ -195,4 +196,4 @@ options &optval;
filename &authref;
filename &mainref;
%end;
%mend ms_runstp;
%mend ms_runstp;

View File

@@ -100,6 +100,11 @@
%end;
%else %if &action=ARR or &action=OBJ %then %do;
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
/* functions in formats unsupported */
%put &sysmacroname: forcing missing back to NULL as feature not supported;
%let missing=NULL;
%end;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,missing=&missing,showmeta=&showmeta
)

View File

@@ -0,0 +1,22 @@
/**
@file
@brief Testing mf_fmtdttm macro
<h4> SAS Macros </h4>
@li mf_fmtdttm.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%global test1;
%mp_assertscope(SNAPSHOT)
%let test1=%mf_fmtdttm();
%mp_assertscope(COMPARE,ignorelist=test1)
%mp_assert(
iftrue=("&test1"="DATETIME19.3" or "&test1"="E8601DT26.6"),
desc=Basic test,
outds=work.test_results
)

View File

@@ -0,0 +1,46 @@
/**
@file
@brief Testing mf_getvarlist macro
<h4> SAS Macros </h4>
@li mf_getvarcount.sas
@li mp_assertscope.sas
**/
data work.all work.nums(keep=num1 num2) work.chars(keep=char1 char2);
length num1 num2 8 char1 char2 char3 $4;
call missing (of _all_);
output;
run;
%mp_assertscope(SNAPSHOT)
%put scope check:%mf_getvarcount(work.all);
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(%mf_getvarcount(work.all)=5),
desc=%str(Checking for mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.all,typefilter=C)=3),
desc=%str(Checking for char in mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.all,typefilter=N)=2),
desc=%str(Checking for num in mixed vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.nums,typefilter=c)=0),
desc=%str(Checking for char in num vars),
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_getvarcount(work.chars,typefilter=N)=0),
desc=%str(Checking for num in char vars),
outds=work.test_results
)

View File

@@ -21,7 +21,8 @@
%mf_mkdir(&root/a/d)
%mf_mkdir(&root/a/e)
%mf_mkdir(&root/a/e/f)
data "&root/a/e/f/ds1.sas7bdat";
libname test "&root/a/e/f";
data test.ds1;
x=1;
run;

View File

@@ -6,11 +6,39 @@
@li mp_filtercheck.sas
@li mp_assertdsobs.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* set up test data */
data work.class ;
length name $8 sex $1 age height weight 8;
infile cards dsd;
input Name:$char. Sex :$char. Age Height Weight;
datalines4;
Alfred,M,14,69,112.5
Alice,F,13,56.5,84
Barbara,F,13,65.3,98
Carol,F,14,62.8,102.5
Henry,M,14,63.5,102.5
James,M,12,57.3,83
Jane,F,12,59.8,84.5
Janet,F,15,62.5,112.5
Jeffrey,M,13,62.5,84
John,M,12,59,99.5
Joyce,F,11,51.3,50.5
Judy,F,14,64.3,90
Louise,F,12,56.3,77
Mary,F,15,66.5,112
Philip,M,16,72,150
Robert,M,12,64.8,128
Ronald,M,15,67,133
Thomas,M,11,57.5,85
William,M,15,66.5,112
;;;;
run;
/* valid filter */
/* valid filter conditions */
data work.inds;
infile datalines4 dsd;
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
@@ -21,14 +49,19 @@ AND,AND,1,SEX,<=,"'M'"
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
AND,OR,2,Weight,>=,77.7
AND,OR,2,Weight,NE,77.7
AND,AND,1,age,=,.A
AND,AND,1,height,<,.B
;;;;
run;
%mp_assertscope(SNAPSHOT)
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
%mp_assertscope(COMPARE)
%let syscc=0;
%mp_assertdsobs(work.badrecords,
desc=Valid filter query,
@@ -49,7 +82,7 @@ AND,OR,2,Weight,>=,7
;;;;
run;
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
@@ -71,7 +104,7 @@ AND,OR,2,Name,NOT IN,"(''''Jane','Alfred')"
run;
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
@@ -94,7 +127,7 @@ AND,OR,2,Weight,>=,7
run;
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
@@ -115,7 +148,7 @@ AND,AND,1,age,=,;;%abort
;;;;
run;
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
@@ -137,7 +170,7 @@ AND,AND,1,age,=,0
run;
%let syscc=0;
%mp_filtercheck(work.inds,
targetds=sashelp.class,
targetds=work.class,
outds=work.badrecords,
abort=NO
)

View File

@@ -11,6 +11,34 @@
options source2;
/* set up test data */
data work.class ;
length name $8 sex $1 age height weight 8;
infile cards dsd;
input Name:$char. Sex :$char. Age Height Weight;
datalines4;
Alfred,M,14,69,112.5
Alice,F,13,56.5,84
Barbara,F,13,65.3,98
Carol,F,14,62.8,102.5
Henry,M,14,63.5,102.5
James,M,12,57.3,83
Jane,F,12,59.8,84.5
Janet,F,15,62.5,112.5
Jeffrey,M,13,62.5,84
John,M,12,59,99.5
Joyce,F,11,51.3,50.5
Judy,F,14,64.3,90
Louise,F,12,56.3,77
Mary,F,15,66.5,112
Philip,M,16,72,150
Robert,M,12,64.8,128
Ronald,M,15,67,133
Thomas,M,11,57.5,85
William,M,15,66.5,112
;;;;
run;
/* valid filter */
data work.inds;
infile datalines4 dsd;
@@ -23,10 +51,10 @@ AND,OR,2,Name,NOT IN,"('Jane','Janet')"
AND,OR,2,Weight,>=,84.6
;;;;
run;
%mp_filtercheck(work.inds,targetds=sashelp.class)
%mp_filtercheck(work.inds,targetds=work.class)
%mp_filtergenerate(work.inds,outref=myfilter)
data work.test;
set sashelp.class;
set work.class;
where %inc myfilter;;
run;
%mp_assertdsobs(work.test,
@@ -43,10 +71,10 @@ data work.inds;
datalines4;
;;;;
run;
%mp_filtercheck(work.inds,targetds=sashelp.class)
%mp_filtercheck(work.inds,targetds=work.class)
%mp_filtergenerate(work.inds,outref=myfilter)
data work.test;
set sashelp.class;
set work.class;
where %inc myfilter;;
run;
%mp_assertdsobs(work.test,
@@ -64,10 +92,10 @@ datalines4;
AND,OR,2,Name,IN,"('Jane','Janet')"
;;;;
run;
%mp_filtercheck(work.inds,targetds=sashelp.class)
%mp_filtercheck(work.inds,targetds=work.class)
%mp_filtergenerate(work.inds,outref=myfilter)
data work.test;
set sashelp.class;
set work.class;
where %inc myfilter;;
run;
%mp_assertdsobs(work.test,
@@ -86,10 +114,10 @@ OR,OR,2,Name,IN,"('Jane','Janet')"
OR,OR,3,Name,IN,"('James')"
;;;;
run;
%mp_filtercheck(work.inds,targetds=sashelp.class)
%mp_filtercheck(work.inds,targetds=work.class)
%mp_filtergenerate(work.inds,outref=myfilter)
data work.test;
set sashelp.class;
set work.class;
where %inc myfilter;;
run;
%mp_assertdsobs(work.test,
@@ -108,10 +136,10 @@ AND,OR,2,Name,IN,"('Jane','Janet')"
AND,OR,3,Name,IN,"('James')"
;;;;
run;
%mp_filtercheck(work.inds,targetds=sashelp.class)
%mp_filtercheck(work.inds,targetds=work.class)
%mp_filtergenerate(work.inds,outref=myfilter)
data work.test;
set sashelp.class;
set work.class;
where %inc myfilter;;
run;
%mp_assertdsobs(work.test,

View File

@@ -10,6 +10,34 @@
**/
/* set up test data */
data work.class ;
length name $8 sex $1 age height weight 8;
infile cards dsd;
input Name:$char. Sex :$char. Age Height Weight;
datalines4;
Alfred,M,14,69,112.5
Alice,F,13,56.5,84
Barbara,F,13,65.3,98
Carol,F,14,62.8,102.5
Henry,M,14,63.5,102.5
James,M,12,57.3,83
Jane,F,12,59.8,84.5
Janet,F,15,62.5,112.5
Jeffrey,M,13,62.5,84
John,M,12,59,99.5
Joyce,F,11,51.3,50.5
Judy,F,14,64.3,90
Louise,F,12,56.3,77
Mary,F,15,66.5,112
Philip,M,16,72,150
Robert,M,12,64.8,128
Ronald,M,15,67,133
Thomas,M,11,57.5,85
William,M,15,66.5,112
;;;;
run;
libname permlib (work);
%mp_coretable(LOCKTABLE,libds=permlib.locktable)
@@ -31,7 +59,7 @@ AND,OR,2,Weight,NE,77.7
;;;;
run;
%mp_filterstore(libds=sashelp.class,
%mp_filterstore(libds=work.class,
queryds=work.inds,
filter_summary=permlib.filtsum,
filter_detail=permlib.filtdet,
@@ -60,7 +88,7 @@ select max(filter_rk) into: test1 from work.result;
)
/* Test 2 - load same table again and ensure we get the same RK */
%mp_filterstore(libds=sashelp.class,
%mp_filterstore(libds=work.class,
queryds=work.inds,
filter_summary=permlib.filtsum,
filter_detail=permlib.filtdet,

View File

@@ -7,9 +7,36 @@
@li mp_filtervalidate.sas
@li mp_assertdsobs.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
data work.class ;
length name $8 sex $1 age height weight 8;
infile cards dsd;
input Name:$char. Sex :$char. Age Height Weight;
datalines4;
Alfred,M,14,69,112.5
Alice,F,13,56.5,84
Barbara,F,13,65.3,98
Carol,F,14,62.8,102.5
Henry,M,14,63.5,102.5
James,M,12,57.3,83
Jane,F,12,59.8,84.5
Janet,F,15,62.5,112.5
Jeffrey,M,13,62.5,84
John,M,12,59,99.5
Joyce,F,11,51.3,50.5
Judy,F,14,64.3,90
Louise,F,12,56.3,77
Mary,F,15,66.5,112
Philip,M,16,72,150
Robert,M,12,64.8,128
Ronald,M,15,67,133
Thomas,M,11,57.5,85
William,M,15,66.5,112
;;;;
run;
/* valid filter */
data work.inds;
@@ -21,10 +48,16 @@ AND,AND,1,AGE,>,5
AND,AND,1,SEX,NE,"'M'"
AND,OR,2,Name,NOT IN,"('Jane','Janet')"
AND,OR,2,Weight,>=,84.6
AND,AND,3,age,=,.a
AND,AND,4,weight,NE,._
;;;;
run;
%mp_filtergenerate(work.inds,outref=myfilter)
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
%mp_assertscope(SNAPSHOT)
%mp_filtervalidate(myfilter,work.class,outds=work.results,abort=NO)
%mp_assertscope(COMPARE)
%mp_assertdsobs(work.results,
desc=Valid filter,
test=EMPTY,
@@ -40,7 +73,7 @@ datalines4;
;;;;
run;
%mp_filtergenerate(work.inds,outref=myfilter)
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
%mp_filtervalidate(myfilter,work.class,outds=work.results,abort=NO)
%mp_assertdsobs(work.results,
desc=Empty filter,
test=EMPTY,
@@ -59,7 +92,7 @@ AND,AND,1,SEX,NE,2
;;;;
run;
%mp_filtergenerate(work.inds,outref=myfilter)
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
%mp_filtervalidate(myfilter,work.class,outds=work.results,abort=NO)
%let syscc=0;
%let test3=0;
data _null_;
@@ -84,7 +117,7 @@ AND,AND,1,age,NE,"'M'"
;;;;
run;
%mp_filtergenerate(work.inds,outref=myfilter)
%mp_filtervalidate(myfilter,sashelp.class,outds=work.results,abort=NO)
%mp_filtervalidate(myfilter,work.class,outds=work.results,abort=NO)
%let syscc=0;
%let test4=0;
data _null_;

Some files were not shown because too many files have changed in this diff Show More