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

Compare commits

...

27 Commits

Author SHA1 Message Date
Allan Bowe
1f369f9848 Merge pull request #266 from sasjs/latin9fixes
fix: writing utf-8 to _webout on windows in a latin9 session causes problems
2022-06-26 23:16:59 +02:00
munja
2372ff5f4f fix: writing utf-8 to _webout on windows in a latin9 session causes problems with subsequent (regular) put statements. The workaround is to write to a different file and stream it back to _webout. 2022-06-26 22:09:54 +01:00
Allan Bowe
6d0e34ba1d Merge pull request #265 from sasjs/binaryfix
enable file copy of files with an encoding that does not match session encoding
2022-06-26 17:14:25 +02:00
munja
7a69698178 fix: adding fileref options and an additional test for mp_binarycopy 2022-06-26 16:12:49 +01:00
Allan Bowe
532bf84e06 fix: mp_jsonout 2022-06-25 21:38:05 +00:00
Allan Bowe
e1afbc02c4 fix: enabling binary copy of files with encoding that does not match session encoding 2022-06-25 21:32:21 +00:00
Allan Bowe
756f00d88d chore: reduce blankspace in compiled streaming apps 2022-06-25 21:30:15 +00:00
Allan Bowe
b72e404d52 Merge pull request #264 from sasjs/allanbowe/add-sysencoding-to-webout-263
feat: adding sysencoding to SASJS and SAS9 server types
2022-06-25 15:16:13 +02:00
Allan Bowe
e31cdeef42 feat: adding sysencoding to SASJS and SAS9 server types
Not added for mv_webout (viya) as that is always UTF-8.  Closes #263
2022-06-25 13:11:14 +00:00
Allan Bowe
8a4e32cc27 chore: updating sasjsconfig 2022-06-21 21:33:33 +00:00
Allan Bowe
f285505b79 Merge pull request #262 from sasjs/allanbowe/mp-ds-cards-does-not-261
fix: special missing support in mp_ds2cards()
2022-06-21 19:37:51 +02:00
Allan Bowe
67f5c50300 fix: special missing support in mp_ds2cards() 2022-06-21 17:34:44 +00:00
Yury Shkoda
ce39e4f779 Merge pull request #260 from sasjs/pr-template
chore(template): added pull request template
2022-06-21 19:57:11 +03:00
Yury Shkoda
9c80f5664c chore(template): added pull request template 2022-06-21 19:51:23 +03:00
Allan Bowe
83466c001b Merge pull request #259 from sasjs/allanbowe/mp-jsonout-not-escaping-258
fix: escaping labels in mp_jsonout when showmeta=YES.  Closes #258
2022-06-21 16:16:07 +02:00
Allan Bowe
ad315be503 fix: escaping labels in mp_jsonout when showmeta=YES. Closes #258 2022-06-21 14:14:35 +00:00
Allan Bowe
c41ae2dcc8 fix: enabling sasjsprocessmode as global var in mp_abort
Also, reduced indentation
2022-06-18 13:11:35 +00:00
d9f8e92fac Merge pull request #257 from sasjs/userfeat
feat: filter mm_getusers on a particular user
2022-06-17 19:59:38 +02:00
Allan Bowe
d42ede15db fix: superq 2022-06-17 17:58:39 +00:00
Allan Bowe
08ea9f7c00 chore: all.sas 2022-06-17 17:55:28 +00:00
Allan Bowe
c327e1fc0d fix: apostrophes 2022-06-17 17:55:01 +00:00
Allan Bowe
02fddcf9a1 fix: removing pipes 2022-06-17 17:51:36 +00:00
Allan Bowe
4752bfbb05 fix: refactor xml 2022-06-17 17:47:34 +00:00
Allan Bowe
767ddd7add feat: filter mm_getusers on a particular user
This can be useful for extracting the uri of a metadata user
2022-06-17 17:03:25 +00:00
Allan Bowe
54a24ced83 fix: using sasjs username in mf_getuser() 2022-06-17 15:54:30 +00:00
Allan Bowe
57ae2981f1 Merge pull request #256 from sasjs/allanbowe/mp-abort-fails-on-windows-254
fix: superq() for sysprocessname
2022-06-17 15:29:22 +02:00
Allan Bowe
a3043ac685 fix: superq() for sysprocessname 2022-06-17 13:28:51 +00:00
16 changed files with 1238 additions and 819 deletions

17
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,17 @@
## Issue
Link any related issue(s) in this section.
## Intent
What this PR intends to achieve.
## Implementation
What code changes have been made to achieve the intent.
## Checks
- [ ] Code is formatted correctly (`sasjs lint`).
- [ ] Any new functionality has been unit tested.
- [ ] All unit tests are passing (`sasjs test`).

575
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -23,18 +23,19 @@
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getuser(type=META %macro mf_getuser(
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local user metavar; %local user;
%if &type=OS %then %let metavar=_secureusername;
%else %let metavar=_metaperson;
%if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; %if %symexist(_sasjs_username) %then %let user=&_sasjs_username;
%else %if %symexist(&metavar) %then %do; %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do;
%if %length(&&&metavar)=0 %then %let user=&sysuserid; %let user=&SYS_COMPUTE_SESSION_OWNER;
%end;
%else %if %symexist(_metaperson) %then %do;
%if %length(&_metaperson)=0 %then %let user=&sysuserid;
/* sometimes SAS will add @domain extension - remove for consistency */ /* sometimes SAS will add @domain extension - remove for consistency */
/* but be sure to quote in case of usernames with commas */ /* but be sure to quote in case of usernames with commas */
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); %else %let user=%unquote(%scan(%quote(&_metaperson),1,@));
%end; %end;
%else %let user=&sysuserid; %else %let user=&sysuserid;

View File

@@ -63,19 +63,19 @@
, mode=REGULAR , mode=REGULAR
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%global sysprocessmode sysprocessname sasjs_stpsrv_header_loc; %global sysprocessmode sysprocessname sasjs_stpsrv_header_loc sasjsprocessmode;
%local fref fid i; %local fref fid i;
%if not(%eval(%unquote(&iftrue))) %then %return; %if not(%eval(%unquote(&iftrue))) %then %return;
%put NOTE: /// mp_abort macro executing //; %put NOTE: /// mp_abort macro executing //;
%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) %if %symexist(_SYSINCLUDEFILEDEVICE)
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */ /* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
and %str(&SYSPROCESSNAME) ne %str(Compute Server) and %superq(SYSPROCESSNAME) ne %str(Compute Server)
%then %do; %then %do;
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do; %if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
data &errds; data &errds;
iftrue='1=1'; iftrue='1=1';
@@ -88,13 +88,13 @@
run; run;
%return; %return;
%end; %end;
%end; %end;
/* Web App Context */ /* Web App Context */
%if %symexist(_PROGRAM) %if %symexist(_PROGRAM)
or %str(&SYSPROCESSNAME) = %str(Compute Server) or %superq(SYSPROCESSNAME) = %str(Compute Server)
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
options obs=max replace mprint; options obs=max replace mprint;
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
%then %do; %then %do;
@@ -288,11 +288,11 @@
%else %do; %else %do;
%abort cancel; %abort cancel;
%end; %end;
%end; %end;
%else %do; %else %do;
%put _all_; %put _all_;
%abort cancel; %abort cancel;
%end; %end;
%mend mp_abort; %mend mp_abort;
/** @endcond */ /** @endcond */

View File

@@ -4,8 +4,8 @@
@details Reads in a file byte by byte and writes it back out. Is an @details Reads in a file byte by byte and writes it back out. Is an
os-independent method to copy files. In case of naming collision, the os-independent method to copy files. In case of naming collision, the
default filerefs can be modified. default filerefs can be modified.
Based on: Note that if you have a new enough version of SAS, and you don't need features
https://stackoverflow.com/questions/13046116/using-sas-to-copy-a-text-file such as APPEND, you may be better of using the fcopy() function instead.
%mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout) %mp_binarycopy(inloc="/home/me/blah.txt", outref=_webout)
@@ -45,14 +45,9 @@
,outref=____out /* override default to use own filerefs */ ,outref=____out /* override default to use own filerefs */
,mode=CREATE ,mode=CREATE
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mod outmode; %local mod;
%if &mode=APPEND %then %do; %if &mode=APPEND %then %let mod=mod;
%let mod=mod;
%let outmode='a';
%end;
%else %do;
%let outmode='o';
%end;
/* these IN and OUT filerefs can point to anything */ /* these IN and OUT filerefs can point to anything */
%if &inref = ____in %then %do; %if &inref = ____in %then %do;
filename &inref &inloc lrecl=1048576 ; filename &inref &inloc lrecl=1048576 ;
@@ -63,18 +58,13 @@
/* copy the file byte-for-byte */ /* copy the file byte-for-byte */
data _null_; data _null_;
length filein 8 fileid 8; infile &inref lrecl=1 recfm=n;
filein = fopen("&inref",'I',1,'B'); file &outref &mod recfm=n;
fileid = fopen("&outref",&outmode,1,'B'); input sourcechar $char1. @@;
rec = '20'x; format sourcechar hex2.;
do while(fread(filein)=0); put sourcechar char1. @@;
rc = fget(filein,rec,1);
rc = fput(fileid, rec);
rc =fwrite(fileid);
end;
rc = fclose(filein);
rc = fclose(fileid);
run; run;
%if &inref = ____in %then %do; %if &inref = ____in %then %do;
filename &inref clear; filename &inref clear;
%end; %end;

View File

@@ -51,7 +51,7 @@
@cond @cond
**/ **/
%macro mp_ds2cards(base_ds=, tgt_ds= %macro mp_ds2cards(base_ds, tgt_ds=
,cards_file="%sysfunc(pathname(work))/cardgen.sas" ,cards_file="%sysfunc(pathname(work))/cardgen.sas"
,maxobs=max ,maxobs=max
,random_sample=NO ,random_sample=NO
@@ -254,6 +254,7 @@ data _null_;
; ;
%end; %end;
put ";"; put ";";
put 'missing a b c d e f g h i j k l m n o p q r s t u v w x y z _;';
put "datalines4;"; put "datalines4;";
end; end;
end; end;

View File

@@ -1,7 +1,12 @@
/** /**
@file mp_jsonout.sas @file mp_jsonout.sas
@brief Writes JSON in SASjs format to a fileref @brief Writes JSON in SASjs format to a fileref
@details PROC JSON is faster but will produce errs like the ones below if @details This macro can be used to OPEN a JSON stream and send one or more
tables as arrays of rows, where each row can be an object or a nested array.
There are two engines available - DATASTEP or PROCJSON.
PROC JSON is fast but will produce errs like the ones below if
special chars are encountered. special chars are encountered.
> (ERR)OR: Some code points did not transcode. > (ERR)OR: Some code points did not transcode.
@@ -12,6 +17,10 @@
If this happens, try running with ENGINE=DATASTEP. If this happens, try running with ENGINE=DATASTEP.
The DATASTEP engine is used to handle special SAS missing numerics, and
can also convert entire datasets to formatted values. Output JSON is always
in UTF-8.
Usage: Usage:
filename tmp temp; filename tmp temp;
@@ -75,9 +84,23 @@
run; run;
%end; %end;
%else %if (&action=ARR or &action=OBJ) %then %do; %else %if (&action=ARR or &action=OBJ) %then %do;
/* force variable names to always be uppercase in the JSON */
options validvarname=upcase; options validvarname=upcase;
data _null_; file &jref encoding='utf-8' mod; /* To avoid issues with _webout on EBI - such as encoding diffs and truncation
(https://support.sas.com/kb/49/325.html) we use temporary files */
filename _sjs1 temp lrecl=200 ;
data _null_; file _sjs1 encoding='utf-8';
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjs1 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs1 clear;
/* grab col defs */ /* grab col defs */
proc contents noprint data=&ds proc contents noprint data=&ds
@@ -134,10 +157,20 @@
data &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 filename _sjs2 temp lrecl=131068 encoding='utf-8';
proc json out=_sjs2 pretty
%if &action=ARR %then nokeys ; %if &action=ARR %then nokeys ;
;export &tempds / nosastags fmtnumeric; ;export &tempds / nosastags fmtnumeric;
run; run;
/* send back to webout */
data _null_;
infile _sjs2 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs2 clear;
%end; %end;
%else %if &engine=DATASTEP %then %do; %else %if &engine=DATASTEP %then %do;
%datastep: %datastep:
@@ -220,10 +253,9 @@
%end; %end;
run; run;
/* write to temp loc to avoid _webout truncation filename _sjs3 temp lrecl=131068 ;
- https://support.sas.com/kb/49/325.html */ data _null_;
filename _sjs temp lrecl=131068 encoding='utf-8'; file _sjs3 encoding='utf-8';
data _null_; file _sjs lrecl=131068 encoding='utf-8' mod ;
if _n_=1 then put "["; if _n_=1 then put "[";
set &tempds; set &tempds;
if _n_>1 then put "," @; put if _n_>1 then put "," @; put
@@ -234,36 +266,34 @@
"&&name&i"n /* name literal for reserved variable names */ "&&name&i"n /* name literal for reserved variable names */
%end; %end;
%if &action=ARR %then "]" ; %else "}" ; ; %if &action=ARR %then "]" ; %else "}" ; ;
/* now write the long strings to _webout 1 byte at a time */
data _null_;
length filein 8 fileid 8;
filein=fopen("_sjs",'I',1,'B');
fileid=fopen("&jref",'A',1,'B');
rec='20'x;
do while(fread(filein)=0);
rc=fget(filein,rec,1);
rc=fput(fileid, rec);
rc=fwrite(fileid);
end;
/* close out the table */ /* close out the table */
rc=fput(fileid, "]"); data _null_;
rc=fwrite(fileid); file _sjs3 mod encoding='utf-8';
rc=fclose(filein); put ']';
rc=fclose(fileid);
run; run;
filename _sjs clear; data _null_;
infile _sjs3 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs3 clear;
%end; %end;
proc sql; proc sql;
drop table &colinfo, &tempds; drop table &colinfo, &tempds;
%if &showmeta=YES %then %do; %if &showmeta=YES %then %do;
data _null_; file &jref encoding='utf-8' mod; filename _sjs4 temp lrecl=131068 encoding='utf-8';
data _null_;
file _sjs4;
put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{";
do i=1 to &numcols; do i=1 to &numcols;
name=quote(trim(symget(cats('name',i)))); name=quote(trim(symget(cats('name',i))));
format=quote(trim(symget(cats('fmt',i)))); format=quote(trim(symget(cats('fmt',i))));
label=quote(trim(symget(cats('label',i)))); label=quote(prxchange('s/\\/\\\\/',-1,trim(symget(cats('label',i)))));
length=quote(trim(symget(cats('length',i)))); length=quote(trim(symget(cats('length',i))));
type=quote(trim(symget(cats('typelong',i)))); type=quote(trim(symget(cats('typelong',i))));
if i>1 then put "," @@; if i>1 then put "," @@;
@@ -272,6 +302,15 @@
end; end;
put '}}'; put '}}';
run; run;
/* send back to webout */
data _null_;
infile _sjs4 lrecl=1 recfm=n;
file &jref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjs4 clear;
%end; %end;
%end; %end;

View File

@@ -17,7 +17,7 @@
%mm_createfolder(path=/some/meta/folder) %mm_createfolder(path=/some/meta/folder)
@param [in] path= Name of the folder to create. @param [in] path= Name of the folder to create.
@param [in] mdebug= set DBG to 1 to disable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version 9.4 @version 9.4

View File

@@ -2,7 +2,8 @@
@file mm_createwebservice.sas @file mm_createwebservice.sas
@brief Create a Web Ready Stored Process @brief Create a Web Ready Stored Process
@details This macro creates a Type 2 Stored Process with the mm_webout macro @details This macro creates a Type 2 Stored Process with the mm_webout macro
included as pre-code. (and dependencies) included as pre-code.
Usage: Usage:
%* compile macros ; %* compile macros ;
@@ -108,9 +109,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -167,10 +182,20 @@ data _null_;
put ' data &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 ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -253,10 +278,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -267,36 +291,34 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 byte at a time */ '; put ' ';
put ' data _null_; ';
put ' length filein 8 fileid 8; ';
put ' filein=fopen("_sjs",''I'',1,''B''); ';
put ' fileid=fopen("&jref",''A'',1,''B''); ';
put ' rec=''20''x; ';
put ' do while(fread(filein)=0); ';
put ' rc=fget(filein,rec,1); ';
put ' rc=fput(fileid, rec); ';
put ' rc=fwrite(fileid); ';
put ' end; ';
put ' /* close out the table */ '; put ' /* close out the table */ ';
put ' rc=fput(fileid, "]"); '; put ' data _null_; ';
put ' rc=fwrite(fileid); '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' rc=fclose(filein); '; put ' put '']''; ';
put ' rc=fclose(fileid); ';
put ' run; '; put ' run; ';
put ' filename _sjs clear; '; put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs3 clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
put ' format=quote(trim(symget(cats(''fmt'',i)))); '; put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
put ' label=quote(trim(symget(cats(''label'',i)))); '; put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
put ' length=quote(trim(symget(cats(''length'',i)))); '; put ' length=quote(trim(symget(cats(''length'',i)))); ';
put ' type=quote(trim(symget(cats(''typelong'',i)))); '; put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
put ' if i>1 then put "," @@; '; put ' if i>1 then put "," @@; ';
@@ -305,6 +327,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -315,18 +346,19 @@ data _null_;
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put ' '; put ' ';
put '%macro mf_getuser(type=META '; put '%macro mf_getuser( ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put ' %local user metavar; '; put ' %local user; ';
put ' %if &type=OS %then %let metavar=_secureusername; ';
put ' %else %let metavar=_metaperson; ';
put ' '; put ' ';
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; '; put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
put ' %end; ';
put ' %else %if %symexist(_metaperson) %then %do; ';
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' /* but be sure to quote in case of usernames with commas */ '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); '; put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';
@@ -405,6 +437,8 @@ data _null_;
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
put ' /* To avoid issues with _webout on EBI we use a temporary file */ ';
put ' filename _sjsref temp lrecl=131068; ';
put ' %if %str(&_debug) ge 131 %then %do; '; put ' %if %str(&_debug) ge 131 %then %do; ';
put ' /* if debug mode, send back first 10 records of each work table also */ '; put ' /* if debug mode, send back first 10 records of each work table also */ ';
put ' options obs=10; '; put ' options obs=10; ';
@@ -418,11 +452,11 @@ data _null_;
put ' i+1; '; put ' i+1; ';
put ' call symputx(cats(''wt'',i),name,''l''); '; put ' call symputx(cats(''wt'',i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); '; put ' call symputx(''wtcnt'',i,''l''); ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put ",""WORK"":{"; '; put ' put ",""WORK"":{"; ';
put ' %do i=1 %to &wtcnt; '; put ' %do i=1 %to &wtcnt; ';
put ' %let wt=&&wt&i; '; put ' %let wt=&&wt&i; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' dsid=open("WORK.&wt",''is''); '; put ' dsid=open("WORK.&wt",''is''); ';
put ' nlobs=attrn(dsid,''NLOBS''); '; put ' nlobs=attrn(dsid,''NLOBS''); ';
put ' nvars=attrn(dsid,''NVARS''); '; put ' nvars=attrn(dsid,''NVARS''); ';
@@ -431,16 +465,16 @@ data _null_;
put ' put " ""&wt"" : {"; '; put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; '; put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; '; put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) '; put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES) ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' %end; '; put ' %end; ';
put ' data _null_; file &fref mod encoding=''utf-8''; '; put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
put ' put "}"; '; put ' put "}"; ';
put ' run; '; put ' run; ';
put ' %end; '; put ' %end; ';
put ' /* close off json */ '; put ' /* close off json */ ';
put ' data _null_;file &fref mod encoding=''utf-8''; '; put ' data _null_;file _sjsref mod encoding=''utf-8''; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); '; put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; '; put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; '; put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
@@ -451,6 +485,7 @@ data _null_;
put ' put '',"_METAPERSON": '' _METAPERSON; '; put ' put '',"_METAPERSON": '' _METAPERSON; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; '; put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; '; put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
@@ -471,6 +506,16 @@ data _null_;
put ' put ''>>weboutEND<<''; '; put ' put ''>>weboutEND<<''; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjsref lrecl=1 recfm=n; ';
put ' file &fref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjsref clear; ';
put ' ';
put '%end; '; put '%end; ';
put ' '; put ' ';
put '%mend mm_webout; '; put '%mend mm_webout; ';
@@ -492,7 +537,7 @@ run;
%if &x>1 %then %let mod=mod; %if &x>1 %then %let mod=mod;
%let fref=%scan(&freflist,&x); %let fref=%scan(&freflist,&x);
%put &sysmacroname: adding &fref; %&mD.put &sysmacroname: adding &fref;
data _null_; data _null_;
file "&work/&tmpfile" lrecl=3000 &mod; file "&work/&tmpfile" lrecl=3000 &mod;
infile &fref; infile &fref;
@@ -528,12 +573,10 @@ data _null_;
if rc=0 then call symputx('url',url,'l'); if rc=0 then call symputx('url',url,'l');
run; run;
%put ;%put ;%put ;%put ;%put ;%put ;
%put &sysmacroname: STP &name successfully created in &path; %put &sysmacroname: STP &name successfully created in &path;
%put ;%put ;%put ;
%put Check it out here:; %put Check it out here:;
%put ;%put ;%put ; %put ;%put ;%put ;
%put &url?_PROGRAM=&path/&name; %put &url?_PROGRAM=&path/&name;
%put ;%put ;%put ;%put ;%put ;%put ; %put ;%put ;%put ;
%mend mm_createwebservice; %mend mm_createwebservice;

View File

@@ -8,17 +8,18 @@
%mm_getusers() %mm_getusers()
Optionally, filter for a user (useful to get the uri):
%mm_getusers(user=&_metaperson)
@param outds the dataset to create that contains the list of libraries @param outds the dataset to create that contains the list of libraries
@returns outds dataset containing all users, with the following columns: @returns outds dataset containing all users, with the following columns:
- uri - uri
- name - name
@warning The following filenames are created and then de-assigned: @param user= (0) Set to a metadata user to filter on that user
@param outds= (work.mm_getusers) The output table to create
filename sxlemap clear;
filename response clear;
libname _XML_ clear;
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
@@ -26,11 +27,13 @@
**/ **/
%macro mm_getusers( %macro mm_getusers(
outds=work.mm_getusers outds=work.mm_getusers,
user=0
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
filename response temp; filename response temp;
proc metadata in= '<GetMetadataObjects> %if %superq(user)=0 %then %do;
proc metadata in= '<GetMetadataObjects>
<Reposid>$METAREPOSITORY</Reposid> <Reposid>$METAREPOSITORY</Reposid>
<Type>Person</Type> <Type>Person</Type>
<NS>SAS</NS> <NS>SAS</NS>
@@ -42,7 +45,31 @@ proc metadata in= '<GetMetadataObjects>
</Options> </Options>
</GetMetadataObjects>' </GetMetadataObjects>'
out=response; out=response;
run; run;
%end;
%else %do;
filename inref temp;
data _null_;
file inref;
put "<GetMetadataObjects>";
put "<Reposid>$METAREPOSITORY</Reposid>";
put "<Type>Person</Type>";
put "<NS>SAS</NS>";
put "<!-- Specify the OMI_XMLSELECT (128) flag -->";
put "<Flags>128</Flags>";
put "<Options>";
put "<Templates>";
put '<Person Name=""/>';
put "</Templates>";
length string $10000;
string=cats('<XMLSELECT search="Person[@Name=',"'&user'",']"/>');
put string;
put "</Options>";
put "</GetMetadataObjects>";
run;
proc metadata in=inref out=response;
run;
%end;
filename sxlemap temp; filename sxlemap temp;
data _null_; data _null_;

View File

@@ -35,6 +35,10 @@
object with the same name as the table but prefixed with a dollar sign - ie, object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}` `,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
@@ -111,6 +115,8 @@
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
/* To avoid issues with _webout on EBI we use a temporary file */
filename _sjsref temp lrecl=131068;
%if %str(&_debug) ge 131 %then %do; %if %str(&_debug) ge 131 %then %do;
/* if debug mode, send back first 10 records of each work table also */ /* if debug mode, send back first 10 records of each work table also */
options obs=10; options obs=10;
@@ -124,11 +130,11 @@
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put ",""WORK"":{"; put ",""WORK"":{";
%do i=1 %to &wtcnt; %do i=1 %to &wtcnt;
%let wt=&&wt&i; %let wt=&&wt&i;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
dsid=open("WORK.&wt",'is'); dsid=open("WORK.&wt",'is');
nlobs=attrn(dsid,'NLOBS'); nlobs=attrn(dsid,'NLOBS');
nvars=attrn(dsid,'NVARS'); nvars=attrn(dsid,'NVARS');
@@ -137,16 +143,16 @@
put " ""&wt"" : {"; put " ""&wt"" : {";
put '"nlobs":' nlobs; put '"nlobs":' nlobs;
put ',"nvars":' nvars; put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=YES)
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
%end; %end;
data _null_; file &fref mod encoding='utf-8'; data _null_; file _sjsref mod encoding='utf-8';
put "}"; put "}";
run; run;
%end; %end;
/* close off json */ /* close off json */
data _null_;file &fref mod encoding='utf-8'; data _null_;file _sjsref mod encoding='utf-8';
_PROGRAM=quote(trim(resolve(symget('_PROGRAM')))); _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" "; put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" "; put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
@@ -157,6 +163,7 @@
put ',"_METAPERSON": ' _METAPERSON; put ',"_METAPERSON": ' _METAPERSON;
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=quote(cats(symget('SYSERRORTEXT'))); syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext; put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" "; put ",""SYSHOSTNAME"" : ""&syshostname"" ";
@@ -177,6 +184,16 @@
put '>>weboutEND<<'; put '>>weboutEND<<';
%end; %end;
run; run;
/* now write to _webout 1 char at a time */
data _null_;
infile _sjsref lrecl=1 recfm=n;
file &fref mod lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
put sourcechar char1. @@;
run;
filename _sjsref clear;
%end; %end;
%mend mm_webout; %mend mm_webout;

View File

@@ -67,7 +67,7 @@
}, },
{ {
"name": "server", "name": "server",
"serverUrl": "https://sas.4gl.io", "serverUrl": "",
"serverType": "SASJS", "serverType": "SASJS",
"httpsAgentOptions": { "httpsAgentOptions": {
"allowInsecureRequests": false "allowInsecureRequests": false

View File

@@ -110,9 +110,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -169,10 +183,20 @@ data _null_;
put ' data &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 ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -255,10 +279,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -269,36 +292,34 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 byte at a time */ '; put ' ';
put ' data _null_; ';
put ' length filein 8 fileid 8; ';
put ' filein=fopen("_sjs",''I'',1,''B''); ';
put ' fileid=fopen("&jref",''A'',1,''B''); ';
put ' rec=''20''x; ';
put ' do while(fread(filein)=0); ';
put ' rc=fget(filein,rec,1); ';
put ' rc=fput(fileid, rec); ';
put ' rc=fwrite(fileid); ';
put ' end; ';
put ' /* close out the table */ '; put ' /* close out the table */ ';
put ' rc=fput(fileid, "]"); '; put ' data _null_; ';
put ' rc=fwrite(fileid); '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' rc=fclose(filein); '; put ' put '']''; ';
put ' rc=fclose(fileid); ';
put ' run; '; put ' run; ';
put ' filename _sjs clear; '; put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs3 clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
put ' format=quote(trim(symget(cats(''fmt'',i)))); '; put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
put ' label=quote(trim(symget(cats(''label'',i)))); '; put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
put ' length=quote(trim(symget(cats(''length'',i)))); '; put ' length=quote(trim(symget(cats(''length'',i)))); ';
put ' type=quote(trim(symget(cats(''typelong'',i)))); '; put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
put ' if i>1 then put "," @@; '; put ' if i>1 then put "," @@; ';
@@ -307,6 +328,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -317,18 +347,19 @@ data _null_;
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put ' '; put ' ';
put '%macro mf_getuser(type=META '; put '%macro mf_getuser( ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put ' %local user metavar; '; put ' %local user; ';
put ' %if &type=OS %then %let metavar=_secureusername; ';
put ' %else %let metavar=_metaperson; ';
put ' '; put ' ';
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; '; put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
put ' %end; ';
put ' %else %if %symexist(_metaperson) %then %do; ';
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' /* but be sure to quote in case of usernames with commas */ '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); '; put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';
@@ -443,6 +474,7 @@ data _null_;
put ' put ",""_DEBUG"" : ""&_debug"" "; '; put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; '; put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; '; put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); '; put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; '; put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); '; put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); ';

View File

@@ -153,6 +153,7 @@
put ",""_DEBUG"" : ""&_debug"" "; put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ; put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" "; put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=quote(cats(symget('SYSERRORTEXT'))); syserrortext=quote(cats(symget('SYSERRORTEXT')));
put ',"SYSERRORTEXT" : ' syserrortext; put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG'))); SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));

View File

@@ -5,6 +5,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_binarycopy.sas @li mp_binarycopy.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_hashdataset.sas
**/ **/
@@ -97,3 +98,39 @@ run;
desc=Append Check (ref to file), desc=Append Check (ref to file),
outds=work.test_results outds=work.test_results
) )
/* test 5 - ensure copy works for binary characters */
/* do this backwards to avoid null chars in JSON preview */
data work.test5;
do i=255 to 1 by -1;
str=byte(i);
output;
end;
run;
/* get an md5 hash of the ds */
%mp_hashdataset(work.test5,outds=myhash)
/* copy it */
%mp_binarycopy(inloc="%sysfunc(pathname(work))/test5.sas7bdat",
outloc="%sysfunc(pathname(work))/test5copy.sas7bdat"
)
/* get an md5 hash of the copied ds */
%mp_hashdataset(work.test5copy,outds=myhash2)
/* compare hashes */
%let test5a=0;
%let test5b=1;
data _null_;
set myhash;
call symputx('test5a',hashkey);
run;
data _null_;
set myhash2;
call symputx('test5b',hashkey);
run;
%mp_assert(
iftrue=("&test5a"="&test5b"),
desc=Ensuring binary copy works on binary characters,
outds=work.test_results
)

View File

@@ -252,9 +252,23 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%else %if (&action=ARR or &action=OBJ) %then %do; '; put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
put ' /* force variable names to always be uppercase in the JSON */ ';
put ' options validvarname=upcase; '; put ' options validvarname=upcase; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' /* To avoid issues with _webout on EBI - such as encoding diffs and truncation ';
put ' (https://support.sas.com/kb/49/325.html) we use temporary files */ ';
put ' filename _sjs1 temp lrecl=200 ; ';
put ' data _null_; file _sjs1 encoding=''utf-8''; ';
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' run; ';
put ' /* now write to _webout 1 char at a time */ ';
put ' data _null_; ';
put ' infile _sjs1 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs1 clear; ';
put ' '; put ' ';
put ' /* grab col defs */ '; put ' /* grab col defs */ ';
put ' proc contents noprint data=&ds '; put ' proc contents noprint data=&ds ';
@@ -311,10 +325,20 @@ data _null_;
put ' data &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 ' filename _sjs2 temp lrecl=131068 encoding=''utf-8''; ';
put ' proc json out=_sjs2 pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs2 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs2 clear; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: '; put ' %datastep: ';
@@ -397,10 +421,9 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' /* write to temp loc to avoid _webout truncation '; put ' filename _sjs3 temp lrecl=131068 ; ';
put ' - https://support.sas.com/kb/49/325.html */ '; put ' data _null_; ';
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; '; put ' file _sjs3 encoding=''utf-8''; ';
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
put ' if _n_=1 then put "["; '; put ' if _n_=1 then put "["; ';
put ' set &tempds; '; put ' set &tempds; ';
put ' if _n_>1 then put "," @; put '; put ' if _n_>1 then put "," @; put ';
@@ -411,36 +434,34 @@ data _null_;
put ' "&&name&i"n /* name literal for reserved variable names */ '; put ' "&&name&i"n /* name literal for reserved variable names */ ';
put ' %end; '; put ' %end; ';
put ' %if &action=ARR %then "]" ; %else "}" ; ; '; put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
put ' /* now write the long strings to _webout 1 byte at a time */ '; put ' ';
put ' data _null_; ';
put ' length filein 8 fileid 8; ';
put ' filein=fopen("_sjs",''I'',1,''B''); ';
put ' fileid=fopen("&jref",''A'',1,''B''); ';
put ' rec=''20''x; ';
put ' do while(fread(filein)=0); ';
put ' rc=fget(filein,rec,1); ';
put ' rc=fput(fileid, rec); ';
put ' rc=fwrite(fileid); ';
put ' end; ';
put ' /* close out the table */ '; put ' /* close out the table */ ';
put ' rc=fput(fileid, "]"); '; put ' data _null_; ';
put ' rc=fwrite(fileid); '; put ' file _sjs3 mod encoding=''utf-8''; ';
put ' rc=fclose(filein); '; put ' put '']''; ';
put ' rc=fclose(fileid); ';
put ' run; '; put ' run; ';
put ' filename _sjs clear; '; put ' data _null_; ';
put ' infile _sjs3 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs3 clear; ';
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' proc sql; '; put ' proc sql; ';
put ' drop table &colinfo, &tempds; '; put ' drop table &colinfo, &tempds; ';
put ' '; put ' ';
put ' %if &showmeta=YES %then %do; '; put ' %if &showmeta=YES %then %do; ';
put ' data _null_; file &jref encoding=''utf-8'' mod; '; put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; '; put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; '; put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); '; put ' name=quote(trim(symget(cats(''name'',i)))); ';
put ' format=quote(trim(symget(cats(''fmt'',i)))); '; put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
put ' label=quote(trim(symget(cats(''label'',i)))); '; put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
put ' length=quote(trim(symget(cats(''length'',i)))); '; put ' length=quote(trim(symget(cats(''length'',i)))); ';
put ' type=quote(trim(symget(cats(''typelong'',i)))); '; put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
put ' if i>1 then put "," @@; '; put ' if i>1 then put "," @@; ';
@@ -449,6 +470,15 @@ data _null_;
put ' end; '; put ' end; ';
put ' put ''}}''; '; put ' put ''}}''; ';
put ' run; '; put ' run; ';
put ' /* send back to webout */ ';
put ' data _null_; ';
put ' infile _sjs4 lrecl=1 recfm=n; ';
put ' file &jref mod lrecl=1 recfm=n; ';
put ' input sourcechar $char1. @@; ';
put ' format sourcechar hex2.; ';
put ' put sourcechar char1. @@; ';
put ' run; ';
put ' filename _sjs4 clear; ';
put ' %end; '; put ' %end; ';
put '%end; '; put '%end; ';
put ' '; put ' ';
@@ -459,18 +489,19 @@ data _null_;
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put ' '; put ' ';
put '%macro mf_getuser(type=META '; put '%macro mf_getuser( ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put ' %local user metavar; '; put ' %local user; ';
put ' %if &type=OS %then %let metavar=_secureusername; ';
put ' %else %let metavar=_metaperson; ';
put ' '; put ' ';
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; '; put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
put ' %end; ';
put ' %else %if %symexist(_metaperson) %then %do; ';
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' /* but be sure to quote in case of usernames with commas */ '; put ' /* but be sure to quote in case of usernames with commas */ ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); '; put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';