mirror of
https://github.com/sasjs/core.git
synced 2026-01-07 01:20:05 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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"
|
||||||
@@ -181,7 +181,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.
|
||||||
@@ -195,7 +195,9 @@ When contributing to this library, it is therefore important to ensure that all
|
|||||||
|
|
||||||
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 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
|
||||||
|
|
||||||
## Star Gazing
|
## Star Gazing
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,41 @@ 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=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 +120,35 @@ 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;
|
%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;
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,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>';
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
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
|
||||||
|
)
|
||||||
|
|
||||||
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)
|
||||||
@@ -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