mirror of
https://github.com/sasjs/core.git
synced 2026-01-03 23:50:06 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb2ccfbbca | ||
|
|
70e508e583 | ||
|
|
8b0acf2eae | ||
|
|
d254870439 | ||
|
|
303225cb85 | ||
|
|
90de167643 | ||
|
|
8ee997de8e | ||
|
|
e27f6ac716 | ||
|
|
ec4de95fcf | ||
|
|
df0fa95519 | ||
|
|
2fe7fba79b | ||
|
|
e40234ee29 | ||
|
|
a287cc27a7 | ||
|
|
921186eb74 | ||
|
|
6fd215ceff | ||
|
|
0297509aa0 | ||
|
|
c5a8bc745d | ||
|
|
36aa466561 | ||
|
|
009485e5b9 | ||
|
|
eb01c8772d | ||
|
|
e3fb69928c | ||
|
|
65afa14466 | ||
|
|
0176b19616 | ||
|
|
9f3dfd9a59 | ||
|
|
513ea354ab | ||
|
|
7b686e11c9 | ||
|
|
3997000266 | ||
|
|
6e177d4cae | ||
|
|
3554991ff8 | ||
|
|
58d2d6382a | ||
|
|
67f28a366c | ||
|
|
64f53acce2 | ||
|
|
2e790f69a1 | ||
|
|
e62011d97e | ||
|
|
cd8d16d09f | ||
|
|
9c61965d4b | ||
|
|
61b8cb5dea | ||
|
|
899f6d9558 | ||
|
|
899de27617 | ||
|
|
322c488e72 | ||
|
|
5d5e66a1c5 | ||
|
|
5f4e9d541d | ||
|
|
306ea93be2 |
9
.github/dependabot.yml
vendored
Normal file
9
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: '/'
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
open-pull-requests-limit: 3
|
||||||
|
allow:
|
||||||
|
- dependency-type: "production"
|
||||||
18
README.md
18
README.md
@@ -81,7 +81,7 @@ Macros used for interfacing with SAS Viya.
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
To contribute, simply write your freeform LUA in the LUA folder. Then run the `build.py`, which will convert your LUA into a data step with put statements, and create the macro wrapper with a `ml_` prefix. You can then use your module in any program by running:
|
To contribute, simply write your freeform LUA in the LUA folder. Then run the `build.py`, which will convert all files with a ".lua" extension into a macro wrapper with an `ml_` prefix (embedding the necessary data step put statements). You can then use your module in any program by running:
|
||||||
|
|
||||||
```sas
|
```sas
|
||||||
/* compile the lua module */
|
/* compile the lua module */
|
||||||
@@ -95,8 +95,7 @@ endsubmit;
|
|||||||
run;
|
run;
|
||||||
```
|
```
|
||||||
|
|
||||||
- X command enabled
|
- Prefixes: _ml_
|
||||||
- Prefixes: _mmw_,_mmu_,_mmx_
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -129,11 +128,11 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
|||||||
- _mf_ for macro functions (can be used in open code).
|
- _mf_ for macro functions (can be used in open code).
|
||||||
- _ml_ for macros that are used to compile LUA modules
|
- _ml_ for macros that are used to compile LUA modules
|
||||||
- _mm_ for metadata macros (interface with the metadata server).
|
- _mm_ for metadata macros (interface with the metadata server).
|
||||||
- _mmx_ for macros that use metadata and are XCMD enabled
|
- _mmx_ for macros that use metadata and are XCMD enabled (working on both windows and unix)
|
||||||
- _mp_ for macro procedures (which generate sas code)
|
- _mp_ for macro procedures (which generate sas code)
|
||||||
- _ms_ for macro procedures that will only work with [@sasjs/server](https://github.com/sasjs/server)
|
- _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
|
- _mv_ for macro procedures that will only work in Viya
|
||||||
- _mx_ for macros that are XCMD enabled
|
- _mx_ for macros that are XCMD enabled (working on both windows and unix)
|
||||||
- follow verb-noun convention
|
- follow verb-noun convention
|
||||||
- unix style line endings (lf)
|
- unix style line endings (lf)
|
||||||
- individual lines should be no more than 80 characters long
|
- individual lines should be no more than 80 characters long
|
||||||
@@ -181,7 +180,7 @@ When contributing to this library, it is therefore important to ensure that all
|
|||||||
- The closing `%mend;` should **not** contain the macro name.
|
- The closing `%mend;` should **not** contain the macro name.
|
||||||
- All macros should be defined with brackets, even if no variables are needed - ie `%macro x();` not `%macro x;`
|
- All macros should be defined with brackets, even if no variables are needed - ie `%macro x();` not `%macro x;`
|
||||||
- Mandatory parameters should be positional, all optional parameters should be keyword (var=) style.
|
- Mandatory parameters should be positional, all optional parameters should be keyword (var=) style.
|
||||||
- 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.
|
- 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 optional unless you are looking to benefit from the timing statistics.
|
- The use of `quit;` for `proc sql` is optional unless you are looking to benefit from the timing statistics.
|
||||||
@@ -193,9 +192,12 @@ When contributing to this library, it is therefore important to ensure that all
|
|||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
||||||
We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major (breaking) release becomes necessary:
|
We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major/breaking release (v5) becomes necessary:
|
||||||
|
|
||||||
* (None as yet)
|
* mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything)
|
||||||
|
* `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed)
|
||||||
|
* mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues.
|
||||||
|
* mp_getddl.sas to be renamed to mp_ds2ddl.sas (consistent with other ds2xxx macros). A wrapper macro is already in place, and you are able to use this immediately. The default for SHOWLOG will also be YES instead of NO.
|
||||||
|
|
||||||
## Star Gazing
|
## Star Gazing
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
@li /data
|
@li /data
|
||||||
@li /jobs
|
@li /jobs
|
||||||
@li /services
|
@li /services
|
||||||
|
@li /tests
|
||||||
@li /tests/jobs
|
@li /tests/jobs
|
||||||
@li /tests/services
|
@li /tests/services
|
||||||
@li /tests/macros
|
@li /tests/macros
|
||||||
@@ -46,9 +47,13 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* First check we are not in the tests/macros folder (which has no subfolders)
|
* First check we are not in the tests/macros folder (which has no subfolders)
|
||||||
|
* or specifically in the testsetup or testteardown services
|
||||||
*/
|
*/
|
||||||
%if %index(&pgm,/tests/macros/) %then %do;
|
%if %index(&pgm,/tests/macros/)
|
||||||
%let root=%substr(&pgm,1,%index(&pgm,/tests/macros)-1);
|
or %index(&pgm,/tests/testsetup)
|
||||||
|
or %index(&pgm,/tests/testteardown)
|
||||||
|
%then %do;
|
||||||
|
%let root=%substr(&pgm,1,%index(&pgm,/tests)-1);
|
||||||
&root
|
&root
|
||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Checks if a set of macro variables exist / contain values.
|
@brief Checks if a set of macro variables exist AND contain values.
|
||||||
@details Writes ERROR to log if abortType is SOFT, else will call %mf_abort.
|
@details Writes ERROR to log if abortType is SOFT, else will call %mf_abort.
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
@@ -14,10 +14,11 @@
|
|||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_abort.sas
|
@li mf_abort.sas
|
||||||
|
|
||||||
@param verifyvars space separated list of macro variable names
|
@param [in] verifyvars Space separated list of macro variable names
|
||||||
@param makeupcase= set to YES to convert all variable VALUES to
|
@param [in] makeupcase= (NO) Set to YES to convert all variable VALUES to
|
||||||
uppercase.
|
uppercase.
|
||||||
@param mAbort= Abort Type. Default is SOFT (writes err to log).
|
@param [in] mAbort= (SOFT) Abort Type. When SOFT, simply writes an err
|
||||||
|
message to the log.
|
||||||
Set to any other value to call mf_abort (which can be configured to abort in
|
Set to any other value to call mf_abort (which can be configured to abort in
|
||||||
various fashions according to context).
|
various fashions according to context).
|
||||||
|
|
||||||
@@ -58,8 +59,14 @@
|
|||||||
|
|
||||||
%goto exit_success;
|
%goto exit_success;
|
||||||
%exit_err:
|
%exit_err:
|
||||||
%if &mAbort=SOFT %then %put %str(ERR)OR: &abortmsg;
|
%put %str(ERR)OR: &abortmsg;
|
||||||
%else %mf_abort(mac=mf_verifymacvars,type=&mabort,msg=&abortmsg);
|
%mf_abort(iftrue=(&mabort ne SOFT),
|
||||||
|
mac=mf_verifymacvars,
|
||||||
|
msg=%str(&abortmsg)
|
||||||
|
)
|
||||||
|
0
|
||||||
|
%return;
|
||||||
%exit_success:
|
%exit_success:
|
||||||
|
1
|
||||||
|
|
||||||
%mend mf_verifymacvars;
|
%mend mf_verifymacvars;
|
||||||
|
|||||||
@@ -66,7 +66,10 @@
|
|||||||
%if %length(&mac)>0 %then %put NOTE- called by &mac;
|
%if %length(&mac)>0 %then %put NOTE- called by &mac;
|
||||||
%put NOTE - &msg;
|
%put NOTE - &msg;
|
||||||
|
|
||||||
%if %symexist(_SYSINCLUDEFILEDEVICE) %then %do;
|
%if %symexist(_SYSINCLUDEFILEDEVICE)
|
||||||
|
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
|
||||||
|
and "&SYSPROCESSNAME " ne "Compute Server "
|
||||||
|
%then %do;
|
||||||
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
|
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
|
||||||
data &errds;
|
data &errds;
|
||||||
iftrue='1=1';
|
iftrue='1=1';
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
make use of permanent tables. To avoid duplication in definitions, this
|
make use of permanent tables. To avoid duplication in definitions, this
|
||||||
macro provides a central location for managing the corresponding DDL.
|
macro provides a central location for managing the corresponding DDL.
|
||||||
|
|
||||||
|
Note - this macro is likely to be deprecated in future in favour of a
|
||||||
|
dedicated "datamodel" folder (prefix mddl)
|
||||||
|
|
||||||
|
Any corresponding data would go in a seperate repo, to avoid this one
|
||||||
|
ballooning in size!
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
%mp_coretable(LOCKTABLE,libds=work.locktable)
|
%mp_coretable(LOCKTABLE,libds=work.locktable)
|
||||||
|
|||||||
@@ -24,20 +24,22 @@ Usage:
|
|||||||
%webout(OBJ,example2) * Object format, easier to work with ;
|
%webout(OBJ,example2) * Object format, easier to work with ;
|
||||||
%webout(CLOSE)
|
%webout(CLOSE)
|
||||||
;;;;
|
;;;;
|
||||||
%mp_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001,replace=YES)
|
%mp_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getplatform.sas
|
@li mf_getplatform.sas
|
||||||
@li mm_createwebservice.sas
|
@li mm_createwebservice.sas
|
||||||
@li mv_createwebservice.sas
|
@li mv_createwebservice.sas
|
||||||
|
|
||||||
@param path= The full folder path where the service will be created
|
@param [in,out] path= The full folder path where the service will be created
|
||||||
@param name= Service name. Avoid spaces.
|
@param [in,out] name= Service name. Avoid spaces.
|
||||||
@param desc= The description of the service (optional)
|
@param [in] desc= The description of the service (optional)
|
||||||
@param precode= Space separated list of filerefs, pointing to the code that
|
@param [in] precode= Space separated list of filerefs, pointing to the code
|
||||||
needs to be attached to the beginning of the service (optional)
|
that needs to be attached to the beginning of the service (optional)
|
||||||
@param code= Space seperated fileref(s) of the actual code to be added
|
@param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
|
||||||
@param replace= select YES to replace any existing service in that location
|
be added
|
||||||
|
@param [in] replace= (YES) Select YES to replace any existing service in that
|
||||||
|
location
|
||||||
|
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
data _null_;
|
data _null_;
|
||||||
set work.&tempds end=last;
|
set work.&tempds end=last;
|
||||||
length fref $8;
|
length fref $8;
|
||||||
|
fref='';
|
||||||
rc=filename(fref,filepath);
|
rc=filename(fref,filepath);
|
||||||
rc=fdelete(fref);
|
rc=fdelete(fref);
|
||||||
if rc then do;
|
if rc then do;
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ data &out_ds(compress=no
|
|||||||
keep=file_or_folder filepath filename ext msg directory level
|
keep=file_or_folder filepath filename ext msg directory level
|
||||||
);
|
);
|
||||||
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80
|
length directory filepath $500 fref fref2 $8 file_or_folder $6 filename $80
|
||||||
ext $20 msg $200;
|
ext $20 msg $200 foption $16;
|
||||||
|
if _n_=1 then call missing(of _all_);
|
||||||
retain level &level;
|
retain level &level;
|
||||||
%if &fref=0 %then %do;
|
%if &fref=0 %then %do;
|
||||||
rc = filename(fref, "&path");
|
rc = filename(fref, "&path");
|
||||||
@@ -93,7 +94,13 @@ data &out_ds(compress=no
|
|||||||
%end;
|
%end;
|
||||||
if rc = 0 then do;
|
if rc = 0 then do;
|
||||||
did = dopen(fref);
|
did = dopen(fref);
|
||||||
directory=dinfo(did,'Directory');
|
/* attribute is OS-dependent - could be "Directory" or "Directory Name" */
|
||||||
|
numopts=doptnum(did);
|
||||||
|
do i=1 to numopts;
|
||||||
|
foption=doptname(did,i);
|
||||||
|
if foption=:'Directory' then i=numopts;
|
||||||
|
end;
|
||||||
|
directory=dinfo(did,foption);
|
||||||
if did=0 then do;
|
if did=0 then do;
|
||||||
putlog "NOTE: This directory is empty - " directory;
|
putlog "NOTE: This directory is empty - " directory;
|
||||||
msg=sysmsg();
|
msg=sysmsg();
|
||||||
|
|||||||
@@ -1,23 +1,82 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Export a dataset to a CSV file
|
@brief Export a dataset to a CSV file WITH leading blanks
|
||||||
@details Export to a file or a fileref
|
@details Export a dataset to a file or fileref, retaining leading blanks.
|
||||||
|
|
||||||
|
When using SASJS headerformat, the input statement is provided in the first
|
||||||
|
row of the CSV.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv")
|
%mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv")
|
||||||
|
|
||||||
@param ds The dataset to be exported
|
filename example temp;
|
||||||
@param outfile= The output filename - should be quoted.
|
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
|
||||||
@param outref= The output fileref (takes precedence if provided)
|
data; infile example; input;put _infile_; if _n_>5 then stop;run;
|
||||||
@param outencoding= The output encoding to use (unquoted)
|
|
||||||
|
data _null_;
|
||||||
|
infile example;
|
||||||
|
input;
|
||||||
|
call symputx('stmnt',_infile_);
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
data work.want;
|
||||||
|
infile example dsd firstobs=2;
|
||||||
|
input &stmnt;
|
||||||
|
run;
|
||||||
|
|
||||||
|
Why use mp_ds2csv over, say, proc export?
|
||||||
|
|
||||||
|
1. Ability to retain leading blanks (this is a major one)
|
||||||
|
2. Control the header format
|
||||||
|
3. Simple one-liner
|
||||||
|
|
||||||
|
@param [in] ds The dataset to be exported
|
||||||
|
@param [in] dlm= (COMMA) The delimeter to apply. For SASJS, will always be
|
||||||
|
COMMA. Supported values:
|
||||||
|
@li COMMA
|
||||||
|
@li SEMICOLON
|
||||||
|
@param [in] headerformat= (LABEL) The format to use for the header section.
|
||||||
|
Valid values:
|
||||||
|
@li LABEL - Use the variable label (or name, if blank)
|
||||||
|
@li NAME - Use the variable name
|
||||||
|
@li SASJS - Used to create sasjs-formatted input CSVs, eg for use in
|
||||||
|
mp_testservice.sas. This format will supply an input statement in the
|
||||||
|
first row, making ingestion by datastep a breeze. Special misisng values
|
||||||
|
will be prefixed with a period (eg `.A`) to enable ingestion on both SAS 9
|
||||||
|
and Viya. Dates / Datetimes etc are identified by the format type (lookup
|
||||||
|
with mcf_getfmttype.sas) and converted to human readable formats (not
|
||||||
|
numbers).
|
||||||
|
@param [out] outfile= The output filename - should be quoted.
|
||||||
|
@param [out] outref= (0) The output fileref (takes precedence if provided)
|
||||||
|
@param [in] outencoding= (0) The (quoted) output encoding to use, eg `"UTF-8"`
|
||||||
|
@param [in] termstr= (CRLF) The line seperator to use. For SASJS, will
|
||||||
|
always be CRLF. Valid values:
|
||||||
|
@li CRLF
|
||||||
|
@li LF
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mcf_getfmttype.sas
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
@li mf_getvarformat.sas
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
@li mf_getvartype.sas
|
||||||
|
|
||||||
@version 9.2
|
@version 9.2
|
||||||
@author Allan Bowe (credit mjsq)
|
@author Allan Bowe (credit mjsq)
|
||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mp_ds2csv(ds, outref=0, outfile=, outencoding=0
|
%macro mp_ds2csv(ds
|
||||||
|
,dlm=COMMA
|
||||||
|
,outref=0
|
||||||
|
,outfile=
|
||||||
|
,outencoding=0
|
||||||
|
,headerformat=LABEL
|
||||||
|
,termstr=CRLF
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%local outloc delim i varlist var vcnt vat dsv vcom vmiss fmttype vfmt;
|
||||||
|
|
||||||
%if not %sysfunc(exist(&ds)) %then %do;
|
%if not %sysfunc(exist(&ds)) %then %do;
|
||||||
%put %str(WARN)ING: &ds does not exist;
|
%put %str(WARN)ING: &ds does not exist;
|
||||||
%return;
|
%return;
|
||||||
@@ -26,33 +85,128 @@
|
|||||||
%if %index(&ds,.)=0 %then %let ds=WORK.&ds;
|
%if %index(&ds,.)=0 %then %let ds=WORK.&ds;
|
||||||
|
|
||||||
%if &outencoding=0 %then %let outencoding=;
|
%if &outencoding=0 %then %let outencoding=;
|
||||||
%else %let outencoding=encoding="&outencoding";
|
%else %let outencoding=encoding=&outencoding;
|
||||||
|
|
||||||
%local outloc;
|
|
||||||
%if &outref=0 %then %let outloc=&outfile;
|
%if &outref=0 %then %let outloc=&outfile;
|
||||||
%else %let outloc=&outref;
|
%else %let outloc=&outref;
|
||||||
|
|
||||||
|
%if &headerformat=SASJS %then %do;
|
||||||
|
%let delim=",";
|
||||||
|
%let termstr=CRLF;
|
||||||
|
%mcf_getfmttype(wrap=YES)
|
||||||
|
%end;
|
||||||
|
%else %if &dlm=COMMA %then %let delim=",";
|
||||||
|
%else %let delim=";";
|
||||||
|
|
||||||
/* credit to mjsq - https://stackoverflow.com/a/55642267 */
|
/* credit to mjsq - https://stackoverflow.com/a/55642267 */
|
||||||
|
|
||||||
/* first get headers */
|
/* first get headers */
|
||||||
data _null_;
|
data _null_;
|
||||||
file &outloc dlm=',' dsd &outencoding lrecl=32767;
|
file &outloc &outencoding lrecl=32767 termstr=&termstr;
|
||||||
length header $ 2000;
|
length header $ 2000 varnm vfmt $32 dlm $1 fmttype $8;
|
||||||
|
call missing(of _all_);
|
||||||
dsid=open("&ds.","i");
|
dsid=open("&ds.","i");
|
||||||
num=attrn(dsid,"nvars");
|
num=attrn(dsid,"nvars");
|
||||||
|
dlm=&delim;
|
||||||
do i=1 to num;
|
do i=1 to num;
|
||||||
header = cats(coalescec(varlabel(dsid,i),varname(dsid,i)));
|
varnm=upcase(varname(dsid,i));
|
||||||
|
if i=num then dlm='';
|
||||||
|
%if &headerformat=NAME %then %do;
|
||||||
|
header=cats(varnm,dlm);
|
||||||
|
%end;
|
||||||
|
%else %if &headerformat=LABEL %then %do;
|
||||||
|
header = cats(coalescec(varlabel(dsid,i),varnm),dlm);
|
||||||
|
%end;
|
||||||
|
%else %if &headerformat=SASJS %then %do;
|
||||||
|
if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.');
|
||||||
|
else do;
|
||||||
|
vfmt=coalescec(varfmt(dsid,i),'0');
|
||||||
|
fmttype=mcf_getfmttype(vfmt);
|
||||||
|
if fmttype='DATE' then header=cats(varnm,':date9.');
|
||||||
|
else if fmttype='DATETIME' then header=cats(varnm,':E8601DT26.6');
|
||||||
|
else if fmttype='TIME' then header=cats(varnm,':TIME12.');
|
||||||
|
else header=cats(varnm,':best.');
|
||||||
|
end;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%put &sysmacroname: Invalid headerformat value (&headerformat);
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
put header @;
|
put header @;
|
||||||
end;
|
end;
|
||||||
rc=close(dsid);
|
rc=close(dsid);
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
%let varlist=%mf_getvarlist(&ds);
|
||||||
|
%let vcnt=%sysfunc(countw(&varlist));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The $quote modifier (without a width) will take the length from the variable
|
||||||
|
* and increase by two. However this will lead to truncation where the value
|
||||||
|
* contains double quotes (which are doubled up). To get around this, scan the
|
||||||
|
* data to see the max number of double quotes, so that the appropriate width
|
||||||
|
* can be applied in the subsequent step.
|
||||||
|
*/
|
||||||
|
data _null_;
|
||||||
|
set &ds end=last;
|
||||||
|
%do i=1 %to &vcnt;
|
||||||
|
%let var=%scan(&varlist,&i);
|
||||||
|
%if %mf_getvartype(&ds,&var)=C %then %do;
|
||||||
|
%let dsv1=%mf_getuniquename(prefix=csvcol1_);
|
||||||
|
%let dsv2=%mf_getuniquename(prefix=csvcol2_);
|
||||||
|
retain &dsv1 0;
|
||||||
|
&dsv2=length(&var)+countc(&var,'"');
|
||||||
|
if &dsv2>&dsv1 then &dsv1=&dsv2;
|
||||||
|
if last then call symputx(
|
||||||
|
"vlen&i"
|
||||||
|
/* should be no shorter than varlen, and no longer than 32767 */
|
||||||
|
,cats('$quote',min(&dsv1+2,32767),'.')
|
||||||
|
,'l'
|
||||||
|
);
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%let vat=@;
|
||||||
|
%let vcom=&delim;
|
||||||
|
%let vmiss=%mf_getuniquename(prefix=csvcol3_);
|
||||||
/* next, export data */
|
/* next, export data */
|
||||||
data _null_;
|
data _null_;
|
||||||
set &ds.;
|
set &ds.;
|
||||||
file &outloc mod dlm=',' dsd &outencoding lrecl=32767;
|
file &outloc mod dlm=&delim dsd &outencoding lrecl=32767 termstr=&termstr;
|
||||||
put (_all_) (+0);
|
if _n_=1 then &vmiss=' ';
|
||||||
|
%do i=1 %to &vcnt;
|
||||||
|
%let var=%scan(&varlist,&i);
|
||||||
|
%if &i=&vcnt %then %do;
|
||||||
|
%let vat=;
|
||||||
|
%let vcom=;
|
||||||
|
%end;
|
||||||
|
%if %mf_getvartype(&ds,&var)=N %then %do;
|
||||||
|
%if &headerformat = SASJS %then %do;
|
||||||
|
%let vcom=&delim;
|
||||||
|
%let fmttype=%sysfunc(mcf_getfmttype(%mf_getvarformat(&ds,&var)0));
|
||||||
|
%if &fmttype=DATE %then %let vfmt=DATE9.;
|
||||||
|
%else %if &fmttype=DATETIME %then %let vfmt=E8601DT26.6;
|
||||||
|
%else %if &fmttype=TIME %then %let vfmt=TIME12.;
|
||||||
|
%else %do;
|
||||||
|
%let vfmt=;
|
||||||
|
%let vcom=;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %let vcom=;
|
||||||
|
|
||||||
|
/* must use period - in order to work in both 9.4 and Viya 3.5 */
|
||||||
|
if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do;
|
||||||
|
&vmiss=cats('.',&var);
|
||||||
|
put &vmiss &vat;
|
||||||
|
end;
|
||||||
|
else put &var &vfmt &vcom &vat;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%if &i ne &vcnt %then %let vcom=&delim;
|
||||||
|
put &var &&vlen&i &vcom &vat;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
%mend mp_ds2csv;
|
%mend mp_ds2csv;
|
||||||
30
base/mp_ds2ddl.sas
Normal file
30
base/mp_ds2ddl.sas
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief A wrapper for mp_getddl.sas
|
||||||
|
@details In the next release, this will be the main version.
|
||||||
|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_getddl.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mp_ds2ddl(libds,fref=getddl,flavour=SAS,showlog=YES,schema=
|
||||||
|
,applydttm=NO
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%local libref;
|
||||||
|
%let libds=%upcase(&libds);
|
||||||
|
%let libref=%scan(&libds,1,.);
|
||||||
|
%if &libref=&libds %then %let libds=WORK.&libds;
|
||||||
|
|
||||||
|
%mp_getddl(%scan(&libds,1,.)
|
||||||
|
,%scan(&libds,2,.)
|
||||||
|
,fref=&fref
|
||||||
|
,flavour=SAS
|
||||||
|
,showlog=&showlog
|
||||||
|
,schema=&schema
|
||||||
|
,applydttm=&applydttm
|
||||||
|
)
|
||||||
|
|
||||||
|
%mend mp_ds2ddl;
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
SYSCC to 1008 if bad records are found, and call mp_abort.sas for a
|
SYSCC to 1008 if bad records are found, and call mp_abort.sas for a
|
||||||
graceful service exit (configurable).
|
graceful service exit (configurable).
|
||||||
|
|
||||||
Used for dynamic filtering in [Data Controller for SAS®](https://datacontroller.io).
|
Used for dynamic filtering in [Data Controller for SAS®](
|
||||||
|
https://datacontroller.io).
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ data &outds;
|
|||||||
output;
|
output;
|
||||||
end;
|
end;
|
||||||
if OPERATOR_NM not in
|
if OPERATOR_NM not in
|
||||||
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS')
|
('=','>','<','<=','>=','BETWEEN','IN','NOT IN','NE','CONTAINS','GE','LE')
|
||||||
then do;
|
then do;
|
||||||
REASON_CD='Invalid OPERATOR_NM: '!!cats(OPERATOR_NM);
|
REASON_CD='Invalid OPERATOR_NM: '!!cats(OPERATOR_NM);
|
||||||
putlog REASON_CD= OPERATOR_NM=;
|
putlog REASON_CD= OPERATOR_NM=;
|
||||||
|
|||||||
@@ -8,8 +8,13 @@
|
|||||||
https://sasapps.io)). This macro is also used in [Data Controller for SAS](
|
https://sasapps.io)). This macro is also used in [Data Controller for SAS](
|
||||||
https://datacontroller.io).
|
https://datacontroller.io).
|
||||||
|
|
||||||
|
A more recent feature of this macro is the ability to support filter queries
|
||||||
|
on Format Catalogs. This is achieved by adding a `-FC` suffix to the `libds`
|
||||||
|
parameter - where the "ds" in this case is the catalog name.
|
||||||
|
|
||||||
@param [in] libds= The target dataset to be filtered (lib should be assigned)
|
|
||||||
|
@param [in] libds= The target dataset to be filtered (lib should be assigned).
|
||||||
|
If filtering a format catalog, add the following suffix: `-FC`.
|
||||||
@param [in] queryds= (WORK.FILTERQUERY) The temporary input query dataset to
|
@param [in] queryds= (WORK.FILTERQUERY) The temporary input query dataset to
|
||||||
be validated. Has the following format:
|
be validated. Has the following format:
|
||||||
|GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$32767|
|
|GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$32767|
|
||||||
@@ -78,7 +83,10 @@
|
|||||||
%put &sysmacroname entry vars:;
|
%put &sysmacroname entry vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
|
|
||||||
%local ds1 ds2 ds3 ds4 filter_hash;
|
%local ds0 ds1 ds2 ds3 ds4 filter_hash orig_libds;
|
||||||
|
%let libds=%upcase(&libds);
|
||||||
|
%let orig_libds=&libds;
|
||||||
|
|
||||||
%mp_abort(iftrue= (&syscc ne 0)
|
%mp_abort(iftrue= (&syscc ne 0)
|
||||||
,mac=mp_filterstore
|
,mac=mp_filterstore
|
||||||
,msg=%str(syscc=&syscc on macro entry)
|
,msg=%str(syscc=&syscc on macro entry)
|
||||||
@@ -96,12 +104,49 @@
|
|||||||
,msg=%str(Invalid lock_table value: &lock_table)
|
,msg=%str(Invalid lock_table value: &lock_table)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* validate query */
|
/**
|
||||||
|
* validate query
|
||||||
|
* use format catalog export, if a format
|
||||||
|
*/
|
||||||
|
%if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do;
|
||||||
|
%let libds=%scan(&libds,1,-); /* chop off -FC extension */
|
||||||
|
%let ds0=%mf_getuniquename(prefix=fmtds_);
|
||||||
|
/*
|
||||||
|
There is no need to export the entire format catalog here - the validations
|
||||||
|
are done against the data model, not the data values. So we can simply
|
||||||
|
hardcode the structure based on the cntlout dataset.
|
||||||
|
*/
|
||||||
|
proc sql;
|
||||||
|
create table &ds0(
|
||||||
|
FMTNAME char(32)
|
||||||
|
,START char(16)
|
||||||
|
,END char(16)
|
||||||
|
,LABEL char(256)
|
||||||
|
,MIN num length=3
|
||||||
|
,MAX num length=3
|
||||||
|
,DEFAULT num length=3
|
||||||
|
,LENGTH num length=3
|
||||||
|
,FUZZ num
|
||||||
|
,PREFIX char(2)
|
||||||
|
,MULT num
|
||||||
|
,FILL char(1)
|
||||||
|
,NOEDIT num length=3
|
||||||
|
,TYPE char(1)
|
||||||
|
,SEXCL char(1)
|
||||||
|
,EEXCL char(1)
|
||||||
|
,HLO char(13)
|
||||||
|
,DECSEP char(1)
|
||||||
|
,DIG3SEP char(1)
|
||||||
|
,DATATYPE char(8)
|
||||||
|
,LANGUAGE char(8)
|
||||||
|
);
|
||||||
|
%let libds=&ds0;
|
||||||
|
%end;
|
||||||
%mp_filtercheck(&queryds,targetds=&libds,abort=YES)
|
%mp_filtercheck(&queryds,targetds=&libds,abort=YES)
|
||||||
|
|
||||||
/* hash the result */
|
/* hash the result */
|
||||||
%let ds1=%mf_getuniquename(prefix=hashds);
|
%let ds1=%mf_getuniquename(prefix=hashds);
|
||||||
%mp_hashdataset(&queryds,outds=&ds1,salt=&libds)
|
%mp_hashdataset(&queryds,outds=&ds1,salt=&orig_libds)
|
||||||
%let filter_hash=%upcase(%mf_getvalue(&ds1,hashkey));
|
%let filter_hash=%upcase(%mf_getvalue(&ds1,hashkey));
|
||||||
%if &mdebug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -132,7 +177,7 @@ run;
|
|||||||
%let ds3=%mf_getuniquename(prefix=filtersum);
|
%let ds3=%mf_getuniquename(prefix=filtersum);
|
||||||
data work.&ds3;
|
data work.&ds3;
|
||||||
if 0 then set &filter_summary;
|
if 0 then set &filter_summary;
|
||||||
filter_table=symget('libds');
|
filter_table="&orig_libds";
|
||||||
filter_hash="&filter_hash";
|
filter_hash="&filter_hash";
|
||||||
PROCESSED_DTTM=%sysfunc(datetime());
|
PROCESSED_DTTM=%sysfunc(datetime());
|
||||||
output;
|
output;
|
||||||
|
|||||||
@@ -96,8 +96,7 @@ filename &fref1 clear;
|
|||||||
run;
|
run;
|
||||||
%mp_abort(
|
%mp_abort(
|
||||||
mac=&sysmacroname,
|
mac=&sysmacroname,
|
||||||
msg=%str(Filter validation issues. ERR=%superq(SYSERRORTEXT)
|
msg=%str(Filter validation issues.)
|
||||||
, WARN=%superq(SYSWARNINGTEXT) )
|
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
%let syscc=1008;
|
%let syscc=1008;
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ create table &outsummary as
|
|||||||
proc format library=&&fmtloc&i CNTLOUT=&tempds;
|
proc format library=&&fmtloc&i CNTLOUT=&tempds;
|
||||||
select &&fmtname&i;
|
select &&fmtname&i;
|
||||||
run;
|
run;
|
||||||
|
data &tempds;
|
||||||
|
length label $256;
|
||||||
|
set &tempds;
|
||||||
|
run;
|
||||||
proc append base=&outdetail data=&tempds;
|
proc append base=&outdetail data=&tempds;
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/mcrolref/n1j5tcc0n2xczyn1
|
|||||||
this dataset.
|
this dataset.
|
||||||
It will then run an abort cancel FILE to stop the include running, and pass
|
It will then run an abort cancel FILE to stop the include running, and pass
|
||||||
the dataset back.
|
the dataset back.
|
||||||
NOTE - it is NOT possible to read this dataset as part of _this_ macro -
|
|
||||||
when running abort cancel FILE, ALL macros are closed, so instead it is
|
IMPORTANT NOTE - it is NOT possible to read this dataset as part of _this_
|
||||||
necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of any macro wrappers.
|
macro! When running abort cancel FILE, ALL macros are closed, so instead it
|
||||||
|
is necessary to invoke "%mp_abort(mode=INCLUDE)" OUTSIDE of macro wrappers.
|
||||||
|
|
||||||
|
|
||||||
@version 9.4
|
@version 9.4
|
||||||
|
|||||||
@@ -53,11 +53,9 @@ data _null_;
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
options
|
options
|
||||||
noautocorrect /* disallow misspelled procedure names */
|
|
||||||
compress=CHAR /* default is none so ensure we have something! */
|
compress=CHAR /* default is none so ensure we have something! */
|
||||||
datastmtchk=ALLKEYWORDS /* protection from overwriting input datasets */
|
datastmtchk=ALLKEYWORDS /* protection from overwriting input datasets */
|
||||||
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
|
errorcheck=STRICT /* catch errs in libname/filename statements */
|
||||||
%str(err)orcheck=STRICT /* catch errs in libname/filename statements */
|
|
||||||
fmterr /* ensure err when a format cannot be found */
|
fmterr /* ensure err when a format cannot be found */
|
||||||
mergenoby=%str(ERR)OR /* throw err when a merge has no BY variables */
|
mergenoby=%str(ERR)OR /* throw err when a merge has no BY variables */
|
||||||
missing=. /* changing this can cause hard to detect errs */
|
missing=. /* changing this can cause hard to detect errs */
|
||||||
@@ -69,6 +67,10 @@ options
|
|||||||
validvarname=V7 /* avoid special characters etc in variable names */
|
validvarname=V7 /* avoid special characters etc in variable names */
|
||||||
varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */
|
varinitchk=%str(ERR)OR /* avoid data mistakes from variable name typos */
|
||||||
varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */
|
varlenchk=%str(ERR)OR /* fail hard if truncation (data loss) can result */
|
||||||
|
%if %substr(&sysver,1,1) ne 4 %then %do;
|
||||||
|
noautocorrect /* disallow misspelled procedure names */
|
||||||
|
dsoptions=note2err /* undocumented - convert bad NOTEs to ERRs */
|
||||||
|
%end;
|
||||||
;
|
;
|
||||||
|
|
||||||
%mend mp_init;
|
%mend mp_init;
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
%put &sysmacroname: Switching to DATASTEP engine;
|
%put &sysmacroname: Switching to DATASTEP engine;
|
||||||
%goto datastep;
|
%goto datastep;
|
||||||
%end;
|
%end;
|
||||||
data &tempds /view=&tempds;set &ds;
|
data &tempds;set &ds;
|
||||||
%if &fmt=N %then format _numeric_ best32.;;
|
%if &fmt=N %then format _numeric_ best32.;;
|
||||||
/* PRETTY is necessary to avoid line truncation in large files */
|
/* PRETTY is necessary to avoid line truncation in large files */
|
||||||
proc json out=&jref pretty
|
proc json out=&jref pretty
|
||||||
@@ -157,7 +157,12 @@
|
|||||||
));
|
));
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
length &&name&i $&&len&i;
|
length &&name&i $&&len&i;
|
||||||
&&name&i=left(put(&&newname&i,&&fmt&i));
|
%if &&typelong&i=num %then %do;
|
||||||
|
&&name&i=left(put(&&newname&i,&&fmt&i));
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
&&name&i=put(&&newname&i,&&fmt&i);
|
||||||
|
%end;
|
||||||
drop &&newname&i;
|
drop &&newname&i;
|
||||||
%end;
|
%end;
|
||||||
if _error_ then call symputx('syscc',1012);
|
if _error_ then call symputx('syscc',1012);
|
||||||
@@ -177,7 +182,7 @@
|
|||||||
%end;
|
%end;
|
||||||
other = [best.];
|
other = [best.];
|
||||||
|
|
||||||
data &tempds/view=&tempds;
|
data &tempds;
|
||||||
attrib _all_ label='';
|
attrib _all_ label='';
|
||||||
%do i=1 %to &numcols;
|
%do i=1 %to &numcols;
|
||||||
%if &&typelong&i=char or &fmt=Y %then %do;
|
%if &&typelong&i=char or &fmt=Y %then %do;
|
||||||
@@ -239,8 +244,7 @@
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
proc sql;
|
proc sql;
|
||||||
drop view &tempds;
|
drop table &colinfo, &tempds;
|
||||||
drop table &colinfo;
|
|
||||||
|
|
||||||
%if &showmeta=YES %then %do;
|
%if &showmeta=YES %then %do;
|
||||||
data _null_; file &jref encoding='utf-8' mod;
|
data _null_; file &jref encoding='utf-8' mod;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ run;
|
|||||||
/* do not proceed if no observations can be processed */
|
/* do not proceed if no observations can be processed */
|
||||||
%mp_abort(iftrue= (%sysfunc(getoption(OBS))=0)
|
%mp_abort(iftrue= (%sysfunc(getoption(OBS))=0)
|
||||||
,mac=&sysmacroname
|
,mac=&sysmacroname
|
||||||
,msg=%str(options obs = 0. syserrortext=&syserrortext)
|
,msg=%str(cannot continue when options obs = 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
%if &ACTION=LOCK %then %do;
|
%if &ACTION=LOCK %then %do;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Prepares an audit table for stacking (re-applying) the changes.
|
@brief Prepares an audit table for stacking (re-applying) the changes.
|
||||||
@details WORK IN PROGRESS!!
|
@details When the underlying data from a Base Table is refreshed, it can be
|
||||||
|
helpful to have any previously-applied changes, re-applied.
|
||||||
When the underlying data from a Base Table is refreshed, it can be helpful
|
|
||||||
to have any previously-applied changes, re-applied.
|
|
||||||
|
|
||||||
Such situation might arise if you are applying those changes using a tool
|
Such situation might arise if you are applying those changes using a tool
|
||||||
like [Data Controller for SAS®](https://datacontroller.io) - which records
|
like [Data Controller for SAS®](https://datacontroller.io) - which records
|
||||||
@@ -23,23 +21,23 @@
|
|||||||
|
|
||||||
Essentially then, what this macro does, is turn a table like this:
|
Essentially then, what this macro does, is turn a table like this:
|
||||||
|
|
||||||
|MOVE_TYPE:$1.|TGTVAR_NM:$32.|IS_PK:best.|IS_DIFF:best.|TGTVAR_TYPE:$1.|OLDVAL_NUM:best32.|NEWVAL_NUM:best32.|OLDVAL_CHAR:$32765.|NEWVAL_CHAR:$32765.|
|
|KEY_HASH:$32.|MOVE_TYPE:$1.|TGTVAR_NM:$32.|IS_PK:best.|IS_DIFF:best.|TGTVAR_TYPE:$1.|OLDVAL_NUM:best32.|NEWVAL_NUM:best32.|OLDVAL_CHAR:$32765.|NEWVAL_CHAR:$32765.|
|
||||||
|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|
|
||||||
|`A `|`NAME `|`1 `|`-1 `|`C `|`. `|`. `|` `|`Newbie `|
|
|`27AA6F7581052E7FF48E1BCA901313FB `|`A `|`NAME `|`1 `|`-1 `|`C `|`. `|`. `|` `|`Newbie `|
|
||||||
|`A `|`AGE `|`0 `|`-1 `|`N `|`. `|`13 `|` `|` `|
|
|`27AA6F7581052E7FF48E1BCA901313FB `|`A `|`AGE `|`0 `|`-1 `|`N `|`. `|`13 `|` `|` `|
|
||||||
|`A `|`HEIGHT `|`0 `|`-1 `|`N `|`. `|`65.3 `|` `|` `|
|
|`27AA6F7581052E7FF48E1BCA901313FB `|`A `|`HEIGHT `|`0 `|`-1 `|`N `|`. `|`65.3 `|` `|` `|
|
||||||
|`A `|`SEX `|`0 `|`-1 `|`C `|`. `|`. `|` `|`F `|
|
|`27AA6F7581052E7FF48E1BCA901313FB `|`A `|`SEX `|`0 `|`-1 `|`C `|`. `|`. `|` `|`F `|
|
||||||
|`A `|`WEIGHT `|`0 `|`-1 `|`N `|`. `|`98 `|` `|` `|
|
|`27AA6F7581052E7FF48E1BCA901313FB `|`A `|`WEIGHT `|`0 `|`-1 `|`N `|`. `|`98 `|` `|` `|
|
||||||
|`D `|`NAME `|`1 `|`-1 `|`C `|`. `|`. `|`Alfred `|` `|
|
|`86703FDE9E87DD5C0F8E1072545D0128 `|`D `|`NAME `|`1 `|`-1 `|`C `|`. `|`. `|`Alfred `|` `|
|
||||||
|`D `|`AGE `|`0 `|`-1 `|`N `|`14 `|`. `|` `|` `|
|
|`86703FDE9E87DD5C0F8E1072545D0128 `|`D `|`AGE `|`0 `|`-1 `|`N `|`14 `|`. `|` `|` `|
|
||||||
|`D `|`HEIGHT `|`0 `|`-1 `|`N `|`69 `|`. `|` `|` `|
|
|`86703FDE9E87DD5C0F8E1072545D0128 `|`D `|`HEIGHT `|`0 `|`-1 `|`N `|`69 `|`. `|` `|` `|
|
||||||
|`D `|`SEX `|`0 `|`-1 `|`C `|`. `|`. `|`M `|` `|
|
|`86703FDE9E87DD5C0F8E1072545D0128 `|`D `|`SEX `|`0 `|`-1 `|`C `|`. `|`. `|`M `|` `|
|
||||||
|`D `|`WEIGHT `|`0 `|`-1 `|`N `|`112.5 `|`. `|` `|` `|
|
|`86703FDE9E87DD5C0F8E1072545D0128 `|`D `|`WEIGHT `|`0 `|`-1 `|`N `|`112.5 `|`. `|` `|` `|
|
||||||
|`M `|`NAME `|`1 `|`0 `|`C `|`. `|`. `|`Alice `|`Alice `|
|
|`64489C85DC2FE0787B85CD87214B3810 `|`M `|`NAME `|`1 `|`0 `|`C `|`. `|`. `|`Alice `|`Alice `|
|
||||||
|`M `|`AGE `|`0 `|`1 `|`N `|`13 `|`99 `|` `|` `|
|
|`64489C85DC2FE0787B85CD87214B3810 `|`M `|`AGE `|`0 `|`1 `|`N `|`13 `|`99 `|` `|` `|
|
||||||
|`M `|`HEIGHT `|`0 `|`0 `|`N `|`56.5 `|`56.5 `|` `|` `|
|
|`64489C85DC2FE0787B85CD87214B3810 `|`M `|`HEIGHT `|`0 `|`0 `|`N `|`56.5 `|`56.5 `|` `|` `|
|
||||||
|`M `|`SEX `|`0 `|`0 `|`C `|`. `|`. `|`F `|`F `|
|
|`64489C85DC2FE0787B85CD87214B3810 `|`M `|`SEX `|`0 `|`0 `|`C `|`. `|`. `|`F `|`F `|
|
||||||
|`M `|`WEIGHT `|`0 `|`0 `|`N `|`84 `|`84 `|` `|` `|
|
|`64489C85DC2FE0787B85CD87214B3810 `|`M `|`WEIGHT `|`0 `|`0 `|`N `|`84 `|`84 `|` `|` `|
|
||||||
|
|
||||||
Into three tables like this:
|
Into three tables like this:
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@
|
|||||||
The macro is also flexible where columns have been added or removed from
|
The macro is also flexible where columns have been added or removed from
|
||||||
the base table UNLESS there is a change to the primary key.
|
the base table UNLESS there is a change to the primary key.
|
||||||
|
|
||||||
Changes to the primary key are NOT supported, and are likely to cause
|
Changes to the primary key fields are NOT supported, and are likely to cause
|
||||||
unexpected results.
|
unexpected results.
|
||||||
|
|
||||||
The following pre-flight checks are made:
|
The following pre-flight checks are made:
|
||||||
@@ -184,7 +182,6 @@
|
|||||||
@param [out] outadd= (work.outadd) Output table containing additional records
|
@param [out] outadd= (work.outadd) Output table containing additional records
|
||||||
@param [out] outdel= (work.outdel) Output table containing deleted records
|
@param [out] outdel= (work.outdel) Output table containing deleted records
|
||||||
|
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_existvarlist.sas
|
@li mf_existvarlist.sas
|
||||||
@li mf_getquotedstr.sas
|
@li mf_getquotedstr.sas
|
||||||
@@ -196,7 +193,6 @@
|
|||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@li mp_ds2squeeze.sas
|
@li mp_ds2squeeze.sas
|
||||||
|
|
||||||
|
|
||||||
<h4> Related Macros </h4>
|
<h4> Related Macros </h4>
|
||||||
@li mp_coretable.sas
|
@li mp_coretable.sas
|
||||||
@li mp_stackdiffs.test.sas
|
@li mp_stackdiffs.test.sas
|
||||||
|
|||||||
@@ -12,17 +12,19 @@
|
|||||||
|
|
||||||
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
|
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
|
||||||
|
|
||||||
|
@param [in] contenttype= (TEXTS) Either TEXT, ZIP, CSV, EXCEL
|
||||||
|
@param [in] inloc= /path/to/file.ext to be sent
|
||||||
|
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
|
||||||
|
@param [in] iftrue= (1=1) Provide a condition under which to execute.
|
||||||
|
@param [out] outname= the name of the file, as downloaded by the browser
|
||||||
|
@param [out] outref= (_webout) The destination where the file should be
|
||||||
|
streamed.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_getplatform.sas
|
@li mf_getplatform.sas
|
||||||
@li mp_binarycopy.sas
|
@li mp_binarycopy.sas
|
||||||
|
|
||||||
@param contenttype= Either TEXT, ZIP, CSV, EXCEL (default TEXT)
|
|
||||||
@param inloc= /path/to/file.ext to be sent
|
|
||||||
@param inref= fileref of file to be sent (if provided, overrides `inloc`)
|
|
||||||
@param outname= the name of the file, as downloaded by the browser
|
|
||||||
|
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
@source https://github.com/sasjs/core
|
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@@ -30,12 +32,16 @@
|
|||||||
contenttype=TEXT
|
contenttype=TEXT
|
||||||
,inloc=
|
,inloc=
|
||||||
,inref=0
|
,inref=0
|
||||||
|
,iftrue=%str(1=1)
|
||||||
,outname=
|
,outname=
|
||||||
|
,outref=_webout
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
%let contentype=%upcase(&contenttype);
|
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||||
%local platform; %let platform=%mf_getplatform();
|
|
||||||
|
|
||||||
|
%let contentype=%upcase(&contenttype);
|
||||||
|
%let outref=%upcase(&outref);
|
||||||
|
%local platform; %let platform=%mf_getplatform();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check engine type to avoid the below err message:
|
* check engine type to avoid the below err message:
|
||||||
@@ -44,20 +50,20 @@
|
|||||||
%local streamweb;
|
%local streamweb;
|
||||||
%let streamweb=0;
|
%let streamweb=0;
|
||||||
data _null_;
|
data _null_;
|
||||||
set sashelp.vextfl(where=(upcase(fileref)="_WEBOUT"));
|
set sashelp.vextfl(where=(upcase(fileref)="&outref"));
|
||||||
if xengine='STREAM' then call symputx('streamweb',1,'l');
|
if xengine='STREAM' then call symputx('streamweb',1,'l');
|
||||||
run;
|
run;
|
||||||
|
|
||||||
%if &contentype=ZIP %then %do;
|
%if &contentype=CSV %then %do;
|
||||||
%if &platform=SASMETA and &streamweb=1 %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/zip');
|
rc=stpsrv_header('Content-type','application/csv');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &platform=SASVIYA %then %do;
|
%else %if &platform=SASVIYA %then %do;
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip'
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
|
||||||
contenttype='application/zip'
|
contenttype='application/csv'
|
||||||
contentdisp="attachment; filename=&outname";
|
contentdisp="attachment; filename=&outname";
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
@@ -70,11 +76,52 @@ run;
|
|||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &platform=SASVIYA %then %do;
|
%else %if &platform=SASVIYA %then %do;
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
|
||||||
contenttype='application/vnd.ms-excel'
|
contenttype='application/vnd.ms-excel'
|
||||||
contentdisp="attachment; filename=&outname";
|
contentdisp="attachment; filename=&outname";
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
|
%else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do;
|
||||||
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
|
data _null_;
|
||||||
|
rc=stpsrv_header('Content-type',"image/%lowcase(&contenttype)");
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%else %if &platform=SASVIYA %then %do;
|
||||||
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI"
|
||||||
|
contenttype="image/%lowcase(&contenttype)";
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %if &contentype=HTML %then %do;
|
||||||
|
%if &platform=SASVIYA %then %do;
|
||||||
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
|
||||||
|
contenttype="text/html";
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %if &contentype=TEXT %then %do;
|
||||||
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
|
data _null_;
|
||||||
|
rc=stpsrv_header('Content-type','application/text');
|
||||||
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%else %if &platform=SASVIYA %then %do;
|
||||||
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
|
||||||
|
contenttype='application/text'
|
||||||
|
contentdisp="attachment; filename=&outname";
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
|
||||||
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
|
data _null_;
|
||||||
|
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)");
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%else %if &platform=SASVIYA %then %do;
|
||||||
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI"
|
||||||
|
contenttype="font/%lowcase(&contenttype)";
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
%else %if &contentype=XLSX %then %do;
|
%else %if &contentype=XLSX %then %do;
|
||||||
%if &platform=SASMETA and &streamweb=1 %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -84,54 +131,34 @@ run;
|
|||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &platform=SASVIYA %then %do;
|
%else %if &platform=SASVIYA %then %do;
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.xls'
|
||||||
contenttype=
|
contenttype=
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
contentdisp="attachment; filename=&outname";
|
contentdisp="attachment; filename=&outname";
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &contentype=TEXT %then %do;
|
%else %if &contentype=ZIP %then %do;
|
||||||
%if &platform=SASMETA and &streamweb=1 %then %do;
|
%if &platform=SASMETA and &streamweb=1 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
rc=stpsrv_header('Content-type','application/text');
|
rc=stpsrv_header('Content-type','application/zip');
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
%else %if &platform=SASVIYA %then %do;
|
%else %if &platform=SASVIYA %then %do;
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
|
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.zip'
|
||||||
contenttype='application/text'
|
contenttype='application/zip'
|
||||||
contentdisp="attachment; filename=&outname";
|
contentdisp="attachment; filename=&outname";
|
||||||
%end;
|
%end;
|
||||||
%end;
|
%end;
|
||||||
%else %if &contentype=CSV %then %do;
|
|
||||||
%if &platform=SASMETA and &streamweb=1 %then %do;
|
|
||||||
data _null_;
|
|
||||||
rc=stpsrv_header('Content-type','application/csv');
|
|
||||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
|
||||||
run;
|
|
||||||
%end;
|
|
||||||
%else %if &platform=SASVIYA %then %do;
|
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name='_webout.txt'
|
|
||||||
contenttype='application/csv'
|
|
||||||
contentdisp="attachment; filename=&outname";
|
|
||||||
%end;
|
|
||||||
%end;
|
|
||||||
%else %if &contentype=HTML %then %do;
|
|
||||||
%if &platform=SASVIYA %then %do;
|
|
||||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
|
|
||||||
contenttype="text/html";
|
|
||||||
%end;
|
|
||||||
%end;
|
|
||||||
%else %do;
|
%else %do;
|
||||||
%put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!;
|
%put %str(ERR)OR: Content Type &contenttype NOT SUPPORTED by &sysmacroname!;
|
||||||
%return;
|
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &inref ne 0 %then %do;
|
%if &inref ne 0 %then %do;
|
||||||
%mp_binarycopy(inref=&inref,outref=_webout)
|
%mp_binarycopy(inref=&inref,outref=&outref)
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%mp_binarycopy(inloc="&inloc",outref=_webout)
|
%mp_binarycopy(inloc="&inloc",outref=&outref)
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend mp_streamfile;
|
%mend mp_streamfile;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
@file mp_testservice.sas
|
@file
|
||||||
@brief Will execute a test against a SASjs web service on SAS 9 or Viya
|
@brief Will execute a SASjs web service on SAS 9 or Viya
|
||||||
@details Prepares the input files and retrieves the resulting datasets from
|
@details Prepares the input files and retrieves the resulting datasets from
|
||||||
the response JSON.
|
the response JSON.
|
||||||
|
|
||||||
%mp_testjob(
|
|
||||||
duration=60*5
|
|
||||||
)
|
|
||||||
|
|
||||||
Note - the _webout fileref should NOT be assigned prior to running this macro.
|
Note - the _webout fileref should NOT be assigned prior to running this macro.
|
||||||
|
|
||||||
@@ -14,6 +12,10 @@
|
|||||||
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
|
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
|
||||||
follows:
|
follows:
|
||||||
inputfiles=inref:filename inref2:filename2
|
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
|
@param [in] inputparams=(0) A dataset containing name/value pairs in the
|
||||||
following format:
|
following format:
|
||||||
|name:$32|value:$1000|
|
|name:$32|value:$1000|
|
||||||
@@ -38,9 +40,13 @@
|
|||||||
@li mf_getuniquename.sas
|
@li mf_getuniquename.sas
|
||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@li mp_binarycopy.sas
|
@li mp_binarycopy.sas
|
||||||
|
@li mp_ds2csv.sas
|
||||||
@li mv_getjobresult.sas
|
@li mv_getjobresult.sas
|
||||||
@li mv_jobflow.sas
|
@li mv_jobflow.sas
|
||||||
|
|
||||||
|
<h4> Related Programs </h4>
|
||||||
|
@li mp_testservice.test.sas
|
||||||
|
|
||||||
@version 9.4
|
@version 9.4
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
@@ -48,6 +54,7 @@
|
|||||||
|
|
||||||
%macro mp_testservice(program,
|
%macro mp_testservice(program,
|
||||||
inputfiles=0,
|
inputfiles=0,
|
||||||
|
inputdatasets=0,
|
||||||
inputparams=0,
|
inputparams=0,
|
||||||
debug=log,
|
debug=log,
|
||||||
mdebug=0,
|
mdebug=0,
|
||||||
@@ -56,7 +63,7 @@
|
|||||||
viyaresult=WEBOUT_JSON,
|
viyaresult=WEBOUT_JSON,
|
||||||
viyacontext=SAS Job Execution compute context
|
viyacontext=SAS Job Execution compute context
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%local dbg;
|
%local dbg pcnt fref1 webref i webcount var platform;
|
||||||
%if &mdebug=1 %then %do;
|
%if &mdebug=1 %then %do;
|
||||||
%put &sysmacroname entry vars:;
|
%put &sysmacroname entry vars:;
|
||||||
%put _local_;
|
%put _local_;
|
||||||
@@ -64,7 +71,6 @@
|
|||||||
%else %let dbg=*;
|
%else %let dbg=*;
|
||||||
|
|
||||||
/* sanitise inputparams */
|
/* sanitise inputparams */
|
||||||
%local pcnt;
|
|
||||||
%let pcnt=0;
|
%let pcnt=0;
|
||||||
%if &inputparams ne 0 %then %do;
|
%if &inputparams ne 0 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -86,17 +92,25 @@
|
|||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
|
||||||
%local fref1 webref;
|
|
||||||
%let fref1=%mf_getuniquefileref();
|
%let fref1=%mf_getuniquefileref();
|
||||||
%let webref=%mf_getuniquefileref();
|
%let webref=%mf_getuniquefileref();
|
||||||
|
|
||||||
%local platform;
|
|
||||||
%let platform=%mf_getplatform();
|
%let platform=%mf_getplatform();
|
||||||
%if &platform=SASMETA %then %do;
|
%if &platform=SASMETA %then %do;
|
||||||
|
|
||||||
/* parse the input files */
|
/* parse the input files */
|
||||||
%local webcount i var;
|
|
||||||
%if %quote(&inputfiles) ne 0 %then %do;
|
%if %quote(&inputfiles) ne 0 %then %do;
|
||||||
%let webcount=%sysfunc(countw(&inputfiles));
|
%let webcount=%sysfunc(countw(&inputfiles));
|
||||||
%put &=webcount;
|
%put &=webcount;
|
||||||
|
|||||||
118
fcmp/mcf_getfmttype.sas
Normal file
118
fcmp/mcf_getfmttype.sas
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Returns the type of the format
|
||||||
|
@details
|
||||||
|
Returns the type, eg DATE / DATETIME / TIME (based on hard-coded lookup)
|
||||||
|
else CHAR / NUM.
|
||||||
|
|
||||||
|
This macro may be extended in the future to support custom formats - this
|
||||||
|
would necessitate a call to `dosubl()` for running a proc format with cntlout.
|
||||||
|
|
||||||
|
The function itself takes the following (positional) parameters:
|
||||||
|
|
||||||
|
| PARAMETER | DESCRIPTION |
|
||||||
|
|---|---|
|
||||||
|
|fmtnm| Format name to be tested. Can be with or without the w.d extension.|
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
fmt1=mcf_getfmttype('DATE9.');
|
||||||
|
fmt2=mcf_getfmttype('DATETIME');
|
||||||
|
put (fmt:)(=);
|
||||||
|
run;
|
||||||
|
%put fmt3=%sysfunc(mcf_getfmttype(TIME9.));
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
> fmt1=DATE fmt2=DATETIME
|
||||||
|
> fmt3=TIME
|
||||||
|
|
||||||
|
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
||||||
|
@param [out] lib= (work) The output library in which to create the catalog.
|
||||||
|
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
||||||
|
@param [out] pkg= (utils) The output package in which to create the function.
|
||||||
|
Uses a 3 part format: libref.catalog.package
|
||||||
|
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
|
||||||
|
values inserted only if needed.
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mcf_init.sas
|
||||||
|
|
||||||
|
<h4> Related Programs </h4>
|
||||||
|
@li mcf_getfmttype.test.sas
|
||||||
|
@li mp_init.sas
|
||||||
|
|
||||||
|
@todo "Custom Format Lookups" To enable site-specific formats, make
|
||||||
|
use of a set of SASJS_FMTLIST_(DATATYPE) global variables.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mcf_getfmttype(wrap=NO
|
||||||
|
,insert_cmplib=DEPRECATED
|
||||||
|
,lib=WORK
|
||||||
|
,cat=SASJS
|
||||||
|
,pkg=UTILS
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
%local i var cmpval found;
|
||||||
|
|
||||||
|
%if %mcf_init(mcf_getfmttype)=1 %then %return;
|
||||||
|
|
||||||
|
%if &wrap=YES %then %do;
|
||||||
|
proc fcmp outlib=&lib..&cat..&pkg;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
function mcf_getfmttype(fmtnm $) $8;
|
||||||
|
if substr(fmtnm,1,1)='$' then return('CHAR');
|
||||||
|
else do;
|
||||||
|
/* extract NAME */
|
||||||
|
length fmt $32;
|
||||||
|
fmt=scan(fmtnm,1,'.');
|
||||||
|
do while (
|
||||||
|
substr(fmt,length(fmt),1) in ('1','2','3','4','5','6','7','8','9','0')
|
||||||
|
);
|
||||||
|
if length(fmt)=1 then fmt='W';
|
||||||
|
else fmt=substr(fmt,1,length(fmt)-1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* apply lookups */
|
||||||
|
if cats(fmt) in ('DATETIME','B8601DN','B8601DN','B8601DT','B8601DT'
|
||||||
|
,'B8601DZ','B8601DZ','DATEAMPM','DTDATE','DTMONYY','DTWKDATX','DTYEAR'
|
||||||
|
,'DTYYQC','E8601DN','E8601DN','E8601DT','E8601DT','E8601DZ','E8601DZ')
|
||||||
|
then return('DATETIME');
|
||||||
|
else if fmt in ('DATE','YYMMDD','B8601DA','B8601DA','DAY','DDMMYY'
|
||||||
|
,'DDMMYYB','DDMMYYC','DDMMYYD','DDMMYYN','DDMMYYP','DDMMYYS','DDMMYYx'
|
||||||
|
,'DOWNAME','E8601DA','E8601DA','JULDAY','JULIAN','MMDDYY','MMDDYYB'
|
||||||
|
,'MMDDYYC','MMDDYYD','MMDDYYN','MMDDYYP','MMDDYYS','MMDDYYx','MMYY'
|
||||||
|
,'MMYYC','MMYYD','MMYYN','MMYYP','MMYYS','MMYYx','MONNAME','MONTH'
|
||||||
|
,'MONYY','PDJULG','PDJULI','QTR','QTRR','WEEKDATE','WEEKDATX','WEEKDAY'
|
||||||
|
,'WEEKU','WEEKV','WEEKW','WORDDATE','WORDDATX','YEAR','YYMM','YYMMC'
|
||||||
|
,'YYMMD','YYMMDDB','YYMMDDC','YYMMDDD','YYMMDDN','YYMMDDP','YYMMDDS'
|
||||||
|
,'YYMMDDx','YYMMN','YYMMP','YYMMS','YYMMx','YYMON','YYQ','YYQC','YYQD'
|
||||||
|
,'YYQN','YYQP','YYQR','YYQRC','YYQRD','YYQRN','YYQRP','YYQRS','YYQRx'
|
||||||
|
,'YYQS','YYQx','YYQZ') then return('DATE');
|
||||||
|
else if fmt in ('TIME','B8601LZ','B8601LZ','B8601TM','B8601TM','B8601TZ'
|
||||||
|
,'B8601TZ','E8601LZ','E8601LZ','E8601TM','E8601TM','E8601TZ','E8601TZ'
|
||||||
|
,'HHMM','HOUR','MMSS','TIMEAMPM','TOD') then return('TIME');
|
||||||
|
else return('NUM');
|
||||||
|
end;
|
||||||
|
endsub;
|
||||||
|
|
||||||
|
%if &wrap=YES %then %do;
|
||||||
|
quit;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* insert the CMPLIB if not already there */
|
||||||
|
%let cmpval=%sysfunc(getoption(cmplib));
|
||||||
|
%let found=0;
|
||||||
|
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
|
||||||
|
%let var=%scan(&cmpval,&i,%str( %(%)));
|
||||||
|
%if &var=&lib..&cat %then %let found=1;
|
||||||
|
%end;
|
||||||
|
%if &found=0 %then %do;
|
||||||
|
options insert=(CMPLIB=(&lib..&cat));
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend mcf_getfmttype;
|
||||||
@@ -32,12 +32,12 @@
|
|||||||
> outa=3 outb=4 outc=5 outd=0
|
> outa=3 outb=4 outc=5 outd=0
|
||||||
|
|
||||||
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
||||||
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
|
|
||||||
CMPLIB reference.
|
|
||||||
@param [out] lib= (work) The output library in which to create the catalog.
|
@param [out] lib= (work) The output library in which to create the catalog.
|
||||||
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
||||||
@param [out] pkg= (utils) The output package in which to create the function.
|
@param [out] pkg= (utils) The output package in which to create the function.
|
||||||
Uses a 3 part format: libref.catalog.package
|
Uses a 3 part format: libref.catalog.package
|
||||||
|
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
|
||||||
|
values inserted only if needed.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mcf_init.sas
|
@li mcf_init.sas
|
||||||
@@ -49,12 +49,12 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mcf_length(wrap=NO
|
%macro mcf_length(wrap=NO
|
||||||
,insert_cmplib=NO
|
,insert_cmplib=DEPRECATED
|
||||||
,lib=WORK
|
,lib=WORK
|
||||||
,cat=SASJS
|
,cat=SASJS
|
||||||
,pkg=UTILS
|
,pkg=UTILS
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
%local i var cmpval found;
|
||||||
%if %mcf_init(mcf_length)=1 %then %return;
|
%if %mcf_init(mcf_length)=1 %then %return;
|
||||||
|
|
||||||
%if &wrap=YES %then %do;
|
%if &wrap=YES %then %do;
|
||||||
@@ -76,7 +76,14 @@ endsub;
|
|||||||
quit;
|
quit;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &insert_cmplib=YES %then %do;
|
/* insert the CMPLIB if not already there */
|
||||||
|
%let cmpval=%sysfunc(getoption(cmplib));
|
||||||
|
%let found=0;
|
||||||
|
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
|
||||||
|
%let var=%scan(&cmpval,&i,%str( %(%)));
|
||||||
|
%if &var=&lib..&cat %then %let found=1;
|
||||||
|
%end;
|
||||||
|
%if &found=0 %then %do;
|
||||||
options insert=(CMPLIB=(&lib..&cat));
|
options insert=(CMPLIB=(&lib..&cat));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,12 @@
|
|||||||
|
|
||||||
|
|
||||||
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
||||||
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
|
|
||||||
CMPLIB reference.
|
|
||||||
@param [out] lib= (work) The output library in which to create the catalog.
|
@param [out] lib= (work) The output library in which to create the catalog.
|
||||||
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
||||||
@param [out] pkg= (utils) The output package in which to create the function.
|
@param [out] pkg= (utils) The output package in which to create the function.
|
||||||
Uses a 3 part format: libref.catalog.package
|
Uses a 3 part format: libref.catalog.package
|
||||||
|
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
|
||||||
|
values inserted only if needed.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mcf_init.sas
|
@li mcf_init.sas
|
||||||
@@ -64,12 +64,12 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mcf_stpsrv_header(wrap=NO
|
%macro mcf_stpsrv_header(wrap=NO
|
||||||
,insert_cmplib=NO
|
,insert_cmplib=DEPRECATED
|
||||||
,lib=WORK
|
,lib=WORK
|
||||||
,cat=SASJS
|
,cat=SASJS
|
||||||
,pkg=UTILS
|
,pkg=UTILS
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
%local i var cmpval found;
|
||||||
%if %mcf_init(stpsrv_header)=1 %then %return;
|
%if %mcf_init(stpsrv_header)=1 %then %return;
|
||||||
|
|
||||||
%if &wrap=YES %then %do;
|
%if &wrap=YES %then %do;
|
||||||
@@ -96,7 +96,14 @@ endsub;
|
|||||||
quit;
|
quit;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &insert_cmplib=YES %then %do;
|
/* insert the CMPLIB if not already there */
|
||||||
|
%let cmpval=%sysfunc(getoption(cmplib));
|
||||||
|
%let found=0;
|
||||||
|
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
|
||||||
|
%let var=%scan(&cmpval,&i,%str( %(%)));
|
||||||
|
%if &var=&lib..&cat %then %let found=1;
|
||||||
|
%end;
|
||||||
|
%if &found=0 %then %do;
|
||||||
options insert=(CMPLIB=(&lib..&cat));
|
options insert=(CMPLIB=(&lib..&cat));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,12 @@
|
|||||||
run;
|
run;
|
||||||
|
|
||||||
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
|
||||||
@param [out] insert_cmplib= (NO) Choose YES to insert the package into the
|
|
||||||
CMPLIB reference.
|
|
||||||
@param [out] lib= (work) The output library in which to create the catalog.
|
@param [out] lib= (work) The output library in which to create the catalog.
|
||||||
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
@param [out] cat= (sasjs) The output catalog in which to create the package.
|
||||||
@param [out] pkg= (utils) The output package in which to create the function.
|
@param [out] pkg= (utils) The output package in which to create the function.
|
||||||
Uses a 3 part format: libref.catalog.package
|
Uses a 3 part format: libref.catalog.package
|
||||||
|
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
|
||||||
|
values inserted only if needed.
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mcf_init.sas
|
@li mcf_init.sas
|
||||||
@@ -49,12 +49,12 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mcf_string2file(wrap=NO
|
%macro mcf_string2file(wrap=NO
|
||||||
,insert_cmplib=NO
|
,insert_cmplib=DEPRECATED
|
||||||
,lib=WORK
|
,lib=WORK
|
||||||
,cat=SASJS
|
,cat=SASJS
|
||||||
,pkg=UTILS
|
,pkg=UTILS
|
||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
|
%local i var cmpval found;
|
||||||
%if %mcf_init(mcf_string2file)=1 %then %return;
|
%if %mcf_init(mcf_string2file)=1 %then %return;
|
||||||
|
|
||||||
%if &wrap=YES %then %do;
|
%if &wrap=YES %then %do;
|
||||||
@@ -81,7 +81,14 @@ endsub;
|
|||||||
quit;
|
quit;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
%if &insert_cmplib=YES %then %do;
|
/* insert the CMPLIB if not already there */
|
||||||
|
%let cmpval=%sysfunc(getoption(cmplib));
|
||||||
|
%let found=0;
|
||||||
|
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
|
||||||
|
%let var=%scan(&cmpval,&i,%str( %(%)));
|
||||||
|
%if &var=&lib..&cat %then %let found=1;
|
||||||
|
%end;
|
||||||
|
%if &found=0 %then %do;
|
||||||
options insert=(CMPLIB=(&lib..&cat));
|
options insert=(CMPLIB=(&lib..&cat));
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,10 @@
|
|||||||
%&mD.put Executing &sysmacroname..sas;
|
%&mD.put Executing &sysmacroname..sas;
|
||||||
%&mD.put _local_;
|
%&mD.put _local_;
|
||||||
|
|
||||||
%mf_verifymacvars(tree name)
|
%mp_abort(iftrue= (%mf_verifymacvars(tree name)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Empty inputs: tree name)
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check tree exists
|
* check tree exists
|
||||||
|
|||||||
@@ -47,7 +47,10 @@
|
|||||||
%&mD.put Executing &sysmacroname..sas;
|
%&mD.put Executing &sysmacroname..sas;
|
||||||
%&mD.put _local_;
|
%&mD.put _local_;
|
||||||
|
|
||||||
%mf_verifymacvars(tree name)
|
%mp_abort(iftrue= (%mf_verifymacvars(tree name)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Empty inputs: tree name)
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check tree exists
|
* check tree exists
|
||||||
|
|||||||
@@ -133,12 +133,14 @@ run;
|
|||||||
filename &frefin temp;
|
filename &frefin temp;
|
||||||
filename &frefout temp;
|
filename &frefout temp;
|
||||||
|
|
||||||
|
%mp_abort(iftrue= (
|
||||||
|
&engine=BASE & %mf_verifymacvars(libname libref engine servercontext tree)=0
|
||||||
|
)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Empty inputs: libname libref engine servercontext tree)
|
||||||
|
)
|
||||||
|
|
||||||
%if &engine=BASE %then %do;
|
%if &engine=BASE %then %do;
|
||||||
|
|
||||||
%mf_verifymacvars(libname libref engine servercontext tree)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the ServerContext exists
|
* Check that the ServerContext exists
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -108,7 +108,12 @@
|
|||||||
%&mD.put Executing mm_CreateSTP.sas;
|
%&mD.put Executing mm_CreateSTP.sas;
|
||||||
%&mD.put _local_;
|
%&mD.put _local_;
|
||||||
|
|
||||||
%mf_verifymacvars(stpname filename directory tree)
|
%mp_abort(
|
||||||
|
iftrue=(%mf_verifymacvars(stpname filename directory tree)=0)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Empty inputs: stpname filename directory tree)
|
||||||
|
)
|
||||||
|
|
||||||
%mp_dropmembers(%scan(&outds,2,.))
|
%mp_dropmembers(%scan(&outds,2,.))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,6 +182,7 @@ run;
|
|||||||
|
|
||||||
data &outds (keep=stpuri prompturi fileuri texturi);
|
data &outds (keep=stpuri prompturi fileuri texturi);
|
||||||
length stpuri prompturi fileuri texturi serveruri $256 ;
|
length stpuri prompturi fileuri texturi serveruri $256 ;
|
||||||
|
if _n_=1 then call missing (of _all_);
|
||||||
set &outds;
|
set &outds;
|
||||||
|
|
||||||
/* final checks on uris */
|
/* final checks on uris */
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ data _null_;
|
|||||||
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
|
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
|
||||||
put ' %goto datastep; ';
|
put ' %goto datastep; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' data &tempds /view=&tempds;set &ds; ';
|
put ' data &tempds;set &ds; ';
|
||||||
put ' %if &fmt=N %then format _numeric_ best32.;; ';
|
put ' %if &fmt=N %then format _numeric_ best32.;; ';
|
||||||
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
|
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
|
||||||
put ' proc json out=&jref pretty ';
|
put ' proc json out=&jref pretty ';
|
||||||
@@ -190,7 +190,12 @@ data _null_;
|
|||||||
put ' )); ';
|
put ' )); ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' length &&name&i $&&len&i; ';
|
put ' length &&name&i $&&len&i; ';
|
||||||
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
|
put ' %if &&typelong&i=num %then %do; ';
|
||||||
|
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' %else %do; ';
|
||||||
|
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||||
|
put ' %end; ';
|
||||||
put ' drop &&newname&i; ';
|
put ' drop &&newname&i; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
put ' if _error_ then call symputx(''syscc'',1012); ';
|
||||||
@@ -210,7 +215,7 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' other = [best.]; ';
|
put ' other = [best.]; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' data &tempds/view=&tempds; ';
|
put ' data &tempds; ';
|
||||||
put ' attrib _all_ label=''''; ';
|
put ' attrib _all_ label=''''; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||||
@@ -272,8 +277,7 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' proc sql; ';
|
put ' proc sql; ';
|
||||||
put ' drop view &tempds; ';
|
put ' drop table &colinfo, &tempds; ';
|
||||||
put ' drop table &colinfo; ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %if &showmeta=YES %then %do; ';
|
put ' %if &showmeta=YES %then %do; ';
|
||||||
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ run;
|
|||||||
|
|
||||||
filename __mc1 temp;
|
filename __mc1 temp;
|
||||||
filename __mc2 temp;
|
filename __mc2 temp;
|
||||||
data &outds; length serveruri servername $200; stop;run;
|
data &outds;
|
||||||
|
length serveruri servername $200;
|
||||||
|
call missing (of _all_);
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
%do x=1 %to &repocnt;
|
%do x=1 %to &repocnt;
|
||||||
options metarepository=&&repo&x;
|
options metarepository=&&repo&x;
|
||||||
proc metadata in=
|
proc metadata in=
|
||||||
@@ -60,13 +64,16 @@ data &outds; length serveruri servername $200; stop;run;
|
|||||||
data _null_;
|
data _null_;
|
||||||
file __mc2;
|
file __mc2;
|
||||||
put '<SXLEMAP version="1.2" name="SASContexts"><TABLE name="SASContexts">';
|
put '<SXLEMAP version="1.2" name="SASContexts"><TABLE name="SASContexts">';
|
||||||
put "<TABLE-PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext</TABLE-PATH>";
|
put "<TABLE-PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext";
|
||||||
|
put "</TABLE-PATH>";
|
||||||
put '<COLUMN name="serveruri">';
|
put '<COLUMN name="serveruri">';
|
||||||
put "<PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext/@Id</PATH>";
|
put "<PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext/@Id";
|
||||||
|
put "</PATH>";
|
||||||
put "<TYPE>character</TYPE><DATATYPE>string</DATATYPE><LENGTH>200</LENGTH>";
|
put "<TYPE>character</TYPE><DATATYPE>string</DATATYPE><LENGTH>200</LENGTH>";
|
||||||
put '</COLUMN>';
|
put '</COLUMN>';
|
||||||
put '<COLUMN name="servername">';
|
put '<COLUMN name="servername">';
|
||||||
put "<PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext/@Name</PATH>";
|
put "<PATH syntax='XPath'>/GetMetadataObjects/Objects/ServerContext/@Name";
|
||||||
|
put "</PATH>";
|
||||||
put "<TYPE>character</TYPE><DATATYPE>string</DATATYPE><LENGTH>200</LENGTH>";
|
put "<TYPE>character</TYPE><DATATYPE>string</DATATYPE><LENGTH>200</LENGTH>";
|
||||||
put '</COLUMN>';
|
put '</COLUMN>';
|
||||||
put '</TABLE></SXLEMAP>';
|
put '</TABLE></SXLEMAP>';
|
||||||
|
|||||||
432
package-lock.json
generated
432
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
|||||||
"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"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sasjs/cli": "3.6.0"
|
"@sasjs/cli": "3.6.0",
|
||||||
|
"@sasjs/core": "4.4.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
"tests/sas9only"
|
"tests/sas9only"
|
||||||
],
|
],
|
||||||
"programFolders": [],
|
"programFolders": [],
|
||||||
|
"binaryFolders": [],
|
||||||
"deployConfig": {
|
"deployConfig": {
|
||||||
"deployServicePack": true,
|
"deployServicePack": true,
|
||||||
"deployScripts": []
|
"deployScripts": []
|
||||||
|
|||||||
39
tests/crossplatform/mcf_getfmttype.test.sas
Normal file
39
tests/crossplatform/mcf_getfmttype.test.sas
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mcf_getfmttype.sas macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mcf_getfmttype.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
|
||||||
|
%mp_assertscope(COMPARE,ignorelist=SASJS_FUNCTIONS)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%sysfunc(mcf_getfmttype(DATE9.))=DATE),
|
||||||
|
desc=Check DATE format
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%sysfunc(mcf_getfmttype($6))=CHAR),
|
||||||
|
desc=Check CHAR format
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%sysfunc(mcf_getfmttype(8.))=NUM),
|
||||||
|
desc=Check NUM format
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%sysfunc(mcf_getfmttype(E8601DT))=DATETIME),
|
||||||
|
desc=Check DATETIME format
|
||||||
|
)
|
||||||
|
|
||||||
|
/* test 2 - compile again test for warnings */
|
||||||
|
%mcf_getfmttype(wrap=YES, insert_cmplib=YES)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Check syscc=0 after re-initialisation
|
||||||
|
)
|
||||||
@@ -46,4 +46,20 @@
|
|||||||
),
|
),
|
||||||
desc=Checking tests/macros appLoc matches (which has no subfolder),
|
desc=Checking tests/macros appLoc matches (which has no subfolder),
|
||||||
outds=work.test_results
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(
|
||||||
|
"%mf_getapploc(/some/area/tests/testsetup)"="/some/area"
|
||||||
|
),
|
||||||
|
desc=Checking tests/testsetup operation,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(
|
||||||
|
"%mf_getapploc(/some/area/tests/testteardown)"="/some/area"
|
||||||
|
),
|
||||||
|
desc=Checking tests/teardown operation,
|
||||||
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
22
tests/crossplatform/mf_verifymacvars.test.sas
Normal file
22
tests/crossplatform/mf_verifymacvars.test.sas
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mf_verifymacvars macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_verifymacvars.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%let var1=x;
|
||||||
|
%let var2=y;
|
||||||
|
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(%mf_verifymacvars(var1 var2)=1),
|
||||||
|
desc=Checking macvars exist,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
166
tests/crossplatform/mp_ds2csv.test.sas
Normal file
166
tests/crossplatform/mp_ds2csv.test.sas
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_ds2csv.sas macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_ds2csv.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
data work.somedata;
|
||||||
|
x=1;
|
||||||
|
y=' t"w"o';
|
||||||
|
z=.z;
|
||||||
|
label x='x factor';
|
||||||
|
run;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 1 - default CSV
|
||||||
|
*/
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mp_ds2csv(work.somedata,outfile="&sasjswork/test1.csv")
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
|
%let test1b=FAIL;
|
||||||
|
data _null_;
|
||||||
|
infile "&sasjswork/test1.csv";
|
||||||
|
input;
|
||||||
|
list;
|
||||||
|
if _n_=1 then call symputx('test1a',_infile_);
|
||||||
|
else if _infile_=:'1," t""w""o",.Z' then call symputx('test1b','PASS');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test1a"="x factor, Y, Z"),
|
||||||
|
desc=Checking header row Test 1,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test1b"="PASS"),
|
||||||
|
desc=Checking data row Test 1,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 2 - NAME header with fileref and semicolons
|
||||||
|
*/
|
||||||
|
filename test2 "&sasjswork/test2.csv";
|
||||||
|
%mp_ds2csv(work.somedata,outref=test2,dlm=SEMICOLON,headerformat=NAME)
|
||||||
|
|
||||||
|
%let test2b=FAIL;
|
||||||
|
data _null_;
|
||||||
|
infile test2;
|
||||||
|
input;
|
||||||
|
list;
|
||||||
|
if _n_=1 then call symputx('test2a',_infile_);
|
||||||
|
else if _infile_=:'1;" t""w""o";.Z' then call symputx('test2b','PASS');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test2a"="X; Y; Z"),
|
||||||
|
desc=Checking header row Test 2,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test2b"="PASS"),
|
||||||
|
desc=Checking data row Test 2,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 3 - SASjs format
|
||||||
|
*/
|
||||||
|
filename test3 "&sasjswork/test3.csv";
|
||||||
|
%mp_ds2csv(work.somedata,outref=test3,headerformat=SASJS)
|
||||||
|
|
||||||
|
%let test3b=FAIL;
|
||||||
|
data _null_;
|
||||||
|
infile test3;
|
||||||
|
input;
|
||||||
|
list;
|
||||||
|
if _n_=1 then call symputx('test3a',_infile_);
|
||||||
|
else if _infile_=:'1," t""w""o",.Z' then call symputx('test3b','PASS');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test3a"="X:best. Y:$char7. Z:best."),
|
||||||
|
desc=Checking header row Test 3,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=("&test3b"="PASS"),
|
||||||
|
desc=Checking data row Test 3,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* test 4 - sasjs with compare */
|
||||||
|
filename example temp;
|
||||||
|
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
|
||||||
|
data _null_; infile example; input;put _infile_; if _n_>5 then stop;run;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile example;
|
||||||
|
input;
|
||||||
|
call symputx('stmnt',_infile_);
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
data work.want;
|
||||||
|
infile example dsd firstobs=2;
|
||||||
|
input &stmnt;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc =0),
|
||||||
|
desc=Checking syscc prior to compare of sashelp.air,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
proc compare base=want compare=sashelp.air;
|
||||||
|
run;
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&sysinfo le 41),
|
||||||
|
desc=Checking compare of sashelp.air,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* test 5 - sasjs with time/datetime/date */
|
||||||
|
filename f2 temp;
|
||||||
|
data work.test5;
|
||||||
|
do x=1 to 5;
|
||||||
|
y=x;
|
||||||
|
z=x;
|
||||||
|
end;
|
||||||
|
format x date9. y datetime19. z time.;
|
||||||
|
run;
|
||||||
|
%mp_ds2csv(work.test5,outref=f2,headerformat=SASJS)
|
||||||
|
data _null_; infile example; input;put _infile_; if _n_>5 then stop;run;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
infile f2;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
call symputx('stmnt2',_infile_);
|
||||||
|
stop;
|
||||||
|
run;
|
||||||
|
data work.want5;
|
||||||
|
infile f2 dsd firstobs=2;
|
||||||
|
input &stmnt2;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Checking syscc prior to compare of test5,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
proc compare base=want5 compare=work.test5;
|
||||||
|
run;
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&sysinfo le 41),
|
||||||
|
desc=Checking compare of work.test5,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
112
tests/crossplatform/mp_filterstore.test.2.sas
Normal file
112
tests/crossplatform/mp_filterstore.test.2.sas
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_filterstore macro with a format catalog
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mp_assertdsobs.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
@li mp_coretable.sas
|
||||||
|
@li mp_filterstore.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
libname permlib (work);
|
||||||
|
|
||||||
|
%mp_coretable(LOCKTABLE,libds=permlib.locktable)
|
||||||
|
%mp_coretable(FILTER_SUMMARY,libds=permlib.filtsum)
|
||||||
|
%mp_coretable(FILTER_DETAIL,libds=permlib.filtdet)
|
||||||
|
%mp_coretable(MAXKEYTABLE,libds=permlib.maxkey)
|
||||||
|
|
||||||
|
/* valid filter */
|
||||||
|
data work.inds;
|
||||||
|
infile datalines4 dsd;
|
||||||
|
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
||||||
|
OPERATOR_NM:$12. RAW_VALUE:$4000.;
|
||||||
|
datalines4;
|
||||||
|
AND,AND,1,Start,>,"'2'"
|
||||||
|
AND,AND,1,Fmtname,=,"'MORDOR'"
|
||||||
|
OR,OR,2,Label,IN,"('Dragon1','Dragon2')"
|
||||||
|
OR,OR,2,End,=,"'6'"
|
||||||
|
OR,OR,2,Start,GE,"'10'"
|
||||||
|
;;;;
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* make some formats */
|
||||||
|
PROC FORMAT library=permlib.testfmts;
|
||||||
|
picture MyMSdt other='%0Y-%0m-%0dT%0H:%0M:%0S' (datatype=datetime);
|
||||||
|
RUN;
|
||||||
|
data work.fmts;
|
||||||
|
length fmtname $32;
|
||||||
|
do fmtname='SMAUG','MORDOR','GOLLUM';
|
||||||
|
do start=1 to 10;
|
||||||
|
label= cats('Dragon ',start);
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
proc sort data=work.fmts nodupkey;
|
||||||
|
by fmtname start;
|
||||||
|
run;
|
||||||
|
proc format cntlin=work.fmts library=permlib.testfmts;
|
||||||
|
run;
|
||||||
|
proc format library=permlib.testfmts;
|
||||||
|
invalue indays (default=13) other=42;
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
%mp_filterstore(libds=permlib.testfmts-fc,
|
||||||
|
queryds=work.inds,
|
||||||
|
filter_summary=permlib.filtsum,
|
||||||
|
filter_detail=permlib.filtdet,
|
||||||
|
lock_table=permlib.locktable,
|
||||||
|
maxkeytable=permlib.maxkey,
|
||||||
|
outresult=work.result,
|
||||||
|
outquery=work.query,
|
||||||
|
mdebug=1
|
||||||
|
)
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
|
%mp_assert(iftrue=(&syscc=0),
|
||||||
|
desc=Ensure macro runs without errors,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
/* ensure only one record created */
|
||||||
|
%mp_assertdsobs(permlib.filtsum,
|
||||||
|
desc=Initial query,
|
||||||
|
test=ATMOST 1,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
/* check RK is correct */
|
||||||
|
proc sql noprint;
|
||||||
|
select max(filter_rk) into: test1 from work.result;
|
||||||
|
%mp_assert(iftrue=(&test1=1),
|
||||||
|
desc=Ensure filter rk is correct,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Test 2 - load same table again and ensure we get the same RK */
|
||||||
|
%mp_filterstore(libds=permlib.testfmts-fc,
|
||||||
|
queryds=work.inds,
|
||||||
|
filter_summary=permlib.filtsum,
|
||||||
|
filter_detail=permlib.filtdet,
|
||||||
|
lock_table=permlib.locktable,
|
||||||
|
maxkeytable=permlib.maxkey,
|
||||||
|
outresult=work.result,
|
||||||
|
outquery=work.query,
|
||||||
|
mdebug=1
|
||||||
|
)
|
||||||
|
/* ensure only one record created */
|
||||||
|
%mp_assertdsobs(permlib.filtsum,
|
||||||
|
desc=Initial query - same obs,
|
||||||
|
test=ATMOST 1,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
/* check RK is correct */
|
||||||
|
proc sql noprint;
|
||||||
|
select max(filter_rk) into: test2 from work.result;
|
||||||
|
%mp_assert(iftrue=(&test2=1),
|
||||||
|
desc=Ensure filter rk is correct for second run,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
28
tests/crossplatform/mp_streamfile.test.sas
Normal file
28
tests/crossplatform/mp_streamfile.test.sas
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_streamfile.sas macro
|
||||||
|
@details This is tricky to test as it streams to webout. For now just
|
||||||
|
check the compilation, and for macro leakage.
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
@li mp_assertscope.sas
|
||||||
|
@li mp_streamfile.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%mp_assertscope(SNAPSHOT)
|
||||||
|
|
||||||
|
%mp_streamfile(iftrue=(1=0)
|
||||||
|
,contenttype=csv,inloc=/some/where.txt
|
||||||
|
,outname=myfile.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_assertscope(COMPARE)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Checking error condition,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
91
tests/crossplatform/mp_testservice.test.sas
Normal file
91
tests/crossplatform/mp_testservice.test.sas
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing mp_testservice.sas macro
|
||||||
|
|
||||||
|
Be sure to run <code>%let mcTestAppLoc=/Public/temp/macrocore;</code> when
|
||||||
|
runnin in Studio
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_createwebservice.sas
|
||||||
|
@li mp_testservice.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
filename ft15f001 temp;
|
||||||
|
parmcards4;
|
||||||
|
%put Initialising sendObj: ;
|
||||||
|
%put _all_;
|
||||||
|
%webout(FETCH)
|
||||||
|
%webout(OPEN)
|
||||||
|
%macro x();
|
||||||
|
%if %symexist(sasjs_tables) %then %do i=1 %to %sysfunc(countw(&sasjs_tables));
|
||||||
|
%let table=%scan(&sasjs_tables,&i);
|
||||||
|
%webout(OBJ,&table,missing=STRING)
|
||||||
|
%end;
|
||||||
|
%else %do i=1 %to &_webin_file_count;
|
||||||
|
%webout(OBJ,&&_webin_name&i,missing=STRING)
|
||||||
|
%end;
|
||||||
|
%mend x; %x()
|
||||||
|
%webout(CLOSE)
|
||||||
|
;;;;
|
||||||
|
%mp_createwebservice(path=&mcTestAppLoc/services,name=sendObj)
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=No errors after service creation,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 1 - send a dataset
|
||||||
|
*/
|
||||||
|
data work.somedata1 work.somedata2;
|
||||||
|
x=1;
|
||||||
|
y=' t"w"o';
|
||||||
|
z=.z;
|
||||||
|
label x='x factor';
|
||||||
|
output;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_testservice(&mcTestAppLoc/services/sendObj,
|
||||||
|
inputdatasets=work.somedata1 work.somedata2,
|
||||||
|
debug=log,
|
||||||
|
mdebug=1,
|
||||||
|
outlib=testlib1,
|
||||||
|
outref=test1
|
||||||
|
)
|
||||||
|
|
||||||
|
%global test1a test1b test1c test1d;
|
||||||
|
data _null_;
|
||||||
|
infile test1;
|
||||||
|
input;
|
||||||
|
putlog _n_ _infile_;
|
||||||
|
if _infile_=', "somedata1":' then call symputx('test1a','PASS');
|
||||||
|
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
||||||
|
call symputx('test1b','PASS');
|
||||||
|
if _infile_='], "somedata2":' then call symputx('test1c','PASS');
|
||||||
|
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
||||||
|
call symputx('test1d','PASS');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test1a=PASS),
|
||||||
|
desc=Test 1 table 1 name,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test1b=PASS),
|
||||||
|
desc=Test 1 table 1 values,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test1c=PASS),
|
||||||
|
desc=Test 1 table 2 name,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test1d=PASS),
|
||||||
|
desc=Test 1 table 2 values,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
@@ -23,4 +23,7 @@
|
|||||||
%end;
|
%end;
|
||||||
%mend loglevel;
|
%mend loglevel;
|
||||||
|
|
||||||
%loglevel()
|
%loglevel()
|
||||||
|
|
||||||
|
%put Initialised &_program;
|
||||||
|
%put _all_;
|
||||||
@@ -2,8 +2,18 @@
|
|||||||
@file
|
@file
|
||||||
@brief term file for tests
|
@brief term file for tests
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_assert.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=Checking final error condition,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
%webout(OPEN)
|
%webout(OPEN)
|
||||||
%webout(OBJ, TEST_RESULTS)
|
%webout(OBJ, TEST_RESULTS)
|
||||||
%webout(CLOSE)
|
%webout(CLOSE)
|
||||||
@@ -76,3 +76,6 @@ run;
|
|||||||
iftrue=(&syscc ne 0),
|
iftrue=(&syscc ne 0),
|
||||||
desc=Check that non zero return code is returned if called job fails
|
desc=Check that non zero return code is returned if called job fails
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* set syscc to zero for final check in testterm */
|
||||||
|
%let syscc=0;
|
||||||
@@ -308,7 +308,7 @@ data _null_;
|
|||||||
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
|
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
|
||||||
put ' %goto datastep; ';
|
put ' %goto datastep; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' data &tempds /view=&tempds;set &ds; ';
|
put ' data &tempds;set &ds; ';
|
||||||
put ' %if &fmt=N %then format _numeric_ best32.;; ';
|
put ' %if &fmt=N %then format _numeric_ best32.;; ';
|
||||||
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
|
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
|
||||||
put ' proc json out=&jref pretty ';
|
put ' proc json out=&jref pretty ';
|
||||||
@@ -334,7 +334,12 @@ data _null_;
|
|||||||
put ' )); ';
|
put ' )); ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' length &&name&i $&&len&i; ';
|
put ' length &&name&i $&&len&i; ';
|
||||||
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
|
put ' %if &&typelong&i=num %then %do; ';
|
||||||
|
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
|
||||||
|
put ' %end; ';
|
||||||
|
put ' %else %do; ';
|
||||||
|
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||||
|
put ' %end; ';
|
||||||
put ' drop &&newname&i; ';
|
put ' drop &&newname&i; ';
|
||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
put ' if _error_ then call symputx(''syscc'',1012); ';
|
||||||
@@ -354,7 +359,7 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' other = [best.]; ';
|
put ' other = [best.]; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' data &tempds/view=&tempds; ';
|
put ' data &tempds; ';
|
||||||
put ' attrib _all_ label=''''; ';
|
put ' attrib _all_ label=''''; ';
|
||||||
put ' %do i=1 %to &numcols; ';
|
put ' %do i=1 %to &numcols; ';
|
||||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||||
@@ -416,8 +421,7 @@ data _null_;
|
|||||||
put ' %end; ';
|
put ' %end; ';
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' proc sql; ';
|
put ' proc sql; ';
|
||||||
put ' drop view &tempds; ';
|
put ' drop table &colinfo, &tempds; ';
|
||||||
put ' drop table &colinfo; ';
|
|
||||||
put ' ';
|
put ' ';
|
||||||
put ' %if &showmeta=YES %then %do; ';
|
put ' %if &showmeta=YES %then %do; ';
|
||||||
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
||||||
|
|||||||
Reference in New Issue
Block a user