1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-31 06:30:05 +00:00

Compare commits

...

37 Commits

Author SHA1 Message Date
Allan Bowe
594a895ddd Merge pull request #296 from sasjs/allanbowe/improve-efficiency-of-295
fix: performance optimisations. closes #295
2022-08-12 19:54:04 +01:00
Allan Bowe
0d59266b8d fix: performance optimisations. closes #295 2022-08-12 18:13:35 +00:00
Allan Bowe
4863aafaa8 Merge pull request #294 from sasjs/allanbowe/add-maxobs-parameter-293
feat: adding maxobs param to mX_webout macros
2022-08-12 14:14:45 +01:00
Allan Bowe
6015320145 feat: adding maxobs param to mX_webout macros 2022-08-12 13:12:06 +00:00
Allan Bowe
8c09c0bce0 Merge pull request #292 from sasjs/allanbowe/increase-length-for-syswarningtext-291
fix: adding length statement for SYSWARNINGTEXT. Closes #291
2022-08-01 11:43:53 +01:00
Allan Bowe
437943b779 fix: adding length statement for SYSWARNINGTEXT. Closes #291 2022-08-01 10:40:55 +00:00
Allan Bowe
6a090e45b6 Merge pull request #290 from sasjs/allanbowe/mp-cleancsv-does-not-289
fix: enable embedded blanks in mp_cleancsv, closes #289
2022-07-21 23:47:18 +01:00
Allan Bowe
a7dc314204 fix: enable embedded blanks in mp_cleancsv, closes #289 2022-07-21 22:40:43 +00:00
munja
37076eae89 feat: new mmx_createmetafolder macro 2022-07-20 19:17:06 +01:00
munja
9a9f8dc847 chore(docs): adding matomo analytics 2022-07-15 16:06:03 +01:00
Allan Bowe
719b657267 Merge pull request #288 from sasjs/allanbowe/mp-jsonout-truncates-287
fix: avoid truncation for formatted outputs
2022-07-14 15:22:20 +01:00
Allan Bowe
671a615501 chore(docs): updated label 2022-07-14 14:18:27 +00:00
Allan Bowe
884b45bf12 fix: avoid truncation for formatted outputs
Closes #287
2022-07-14 14:16:42 +00:00
Allan Bowe
ff6ae1b066 Merge pull request #286 from sasjs/ddlfix
fix: comment issue in DDL generation
2022-07-14 14:03:29 +01:00
Allan Bowe
d581fec55e fix: comment issue in DDL generation 2022-07-14 13:02:15 +00:00
Allan Bowe
a5613a79bb chore(docs): adding SASJedi link to README 2022-07-14 11:42:34 +01:00
Allan Bowe
c6703e16e8 Merge pull request #285 from sasjs/mf_increment
feat: new mf_increment macro
2022-07-14 08:57:49 +01:00
munja
6587dce95b feat: new mf_increment macro 2022-07-13 23:57:02 +01:00
Allan Bowe
b60e6448b9 Merge pull request #284 from sasjs/allanbowe/dictionary-table-constraints-283
fix: avoid exceptions from dictionary.table_constraints.
2022-07-13 19:05:33 +01:00
Allan Bowe
46d9b58b32 fix: avoid exceptions from dictionary.table_constraints.
Closes #283
2022-07-13 18:01:52 +00:00
Allan Bowe
349cbabc94 Merge pull request #282 from sasjs/allanbowe/error-multiple-lengths-281
fix: prevent warning from `_label_` variable with different lengths
2022-07-12 23:29:47 +01:00
Allan Bowe
9de056a3fc fix: prevent warning from _label_ variable with different lengths
Closes #281
2022-07-12 22:18:01 +00:00
Allan Bowe
ad497b322f chore(tests): adding some extra test cases 2022-07-12 15:03:41 +00:00
Allan Bowe
7a6408ee44 Merge pull request #280 from sasjs/allanbowe/support-special-missings-279
fix: supporting special missings in BETWEEN and IN operators
2022-07-08 00:25:53 +01:00
Allan Bowe
336743f2b4 fix: applying logic to BETWEEN as well as IN 2022-07-07 23:24:24 +00:00
Allan Bowe
6e32eb3bd6 fix: supporting special missings in BETWEEN and IN operators
Impacts mp_filtercheck.sas.  Tests added.  Closes #279
2022-07-07 22:47:04 +00:00
Allan Bowe
b377b83442 Merge pull request #278 from sasjs/allanbowe/add-iftrue-parameter-277
fix: iftrue parameter for mp_binarycopy.  Closes #277
2022-07-07 11:29:25 +01:00
Allan Bowe
899b94bb6e fix: iftrue parameter for mp_binarycopy. Closes #277 2022-07-07 10:28:24 +00:00
Allan Bowe
d97efdff61 Merge pull request #276 from sasjs/allanbowe/syswarningtext-with-embedded-275
fix: escaping SYSWARNINGTEXT and SYSERRORTEXT for JSON response
2022-07-06 12:57:19 +01:00
Allan Bowe
1097afbcb8 fix: escaping SYSWARNINGTEXT and SYSERRORTEXT for JSON response
Closes #275
2022-07-06 11:55:15 +00:00
Allan Bowe
165b2d3568 Merge pull request #274 from sasjs/getpk
fix: enabling cross-compatibility of mp_getpk macro
2022-07-04 22:36:10 +01:00
Allan Bowe
44a80c8985 fix: enabling cross-compatibility of mp_getpk macro 2022-07-04 21:32:41 +00:00
Allan Bowe
6e32d9b743 Merge pull request #273 from sasjs/allanbowe/mp-jsonout-fails-in-meta-272
fix: setting length of label property in mp_jsonout
2022-07-04 13:27:02 +01:00
Allan Bowe
6b167e7a4c fix: longer label to allow for escapes 2022-07-04 12:26:19 +00:00
Allan Bowe
011672b1ed fix: setting length of label property in mp_jsonout 2022-07-04 12:24:53 +00:00
Allan Bowe
a7eb926810 Merge pull request #271 from sasjs/ms_getusers
fix: ensuring results when strict mode enabled in ms_getusers
2022-07-02 21:14:06 +01:00
Allan Bowe
cad7f13a0e fix: ensuring results when strict mode enabled in ms_getusers 2022-07-02 20:13:02 +00:00
30 changed files with 990 additions and 287 deletions

View File

@@ -237,6 +237,7 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
The following repositories are also worth checking out:
* [SASJedi/sas-macros](https://github.com/SASJedi/sas-macros)
* [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros)
* [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs)
* [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros)

573
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,11 @@
%else %if "&SYSVLONG" < "9.04.01M3" %then 0;
%else 1;
%end;
%else %if &feature=DBMS_MEMTYPE %then %do;
/* does dbms_memtype exist in dictionary.tables? */
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 0;
%else 1;
%end;
%else %if &feature=EXPORTXLS %then %do;
/* is it possible to PROC EXPORT an excel file? */
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 1;

29
base/mf_increment.sas Normal file
View File

@@ -0,0 +1,29 @@
/**
@file
@brief Increments a macro variable
@details Useful outside of do-loops - will increment a macro variable every
time it is called.
Example:
%let cnt=1;
%put We have run %mf_increment(cnt) lines;
%put Now we have run %mf_increment(cnt) lines;
%put There are %mf_increment(cnt) lines in total;
@param [in] MACRO_NAME the name of the macro variable to increment
@param [in] ITER= The amount to add or subtract to the macro
<h4> Related Files </h4>
@li mf_increment.test.sas
**/
%macro mf_increment(macro_name,incr=1);
/* iterate the value */
%let &macro_name=%eval(&&&macro_name+&incr);
/* return the value */
&&&macro_name
%mend mf_increment;

View File

@@ -225,7 +225,7 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=quote(trim(symget('syserrortext')));
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ",""SYSERRORTEXT"" : " syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
@@ -233,7 +233,7 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=quote(trim(symget('syswarningtext')));
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
put ",""SYSWARNINGTEXT"" : " syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
put "}" ;

View File

@@ -31,6 +31,7 @@
@param [in] mode (CREATE) Valid values:
@li CREATE - Create the file (even if it already exists)
@li APPEND - Append to the file (don't overwrite)
@param iftrue= (1=1) Supply a condition for which the macro should be executed
@returns nothing
@@ -44,8 +45,12 @@
,inref=____in /* override default to use own filerefs */
,outref=____out /* override default to use own filerefs */
,mode=CREATE
,iftrue=%str(1=1)
)/*/STORE SOURCE*/;
%local mod;
%if not(%eval(%unquote(&iftrue))) %then %return;
%if &mode=APPEND %then %let mod=mod;
/* these IN and OUT filerefs can point to anything */

View File

@@ -1,5 +1,5 @@
/**
@file mp_cleancsv.sas
@file
@brief Fixes embedded cr / lf / crlf in CSV
@details CSVs will sometimes contain lf or crlf within quotes (eg when
saved by excel). When the termstr is ALSO lf or crlf that can be tricky
@@ -7,14 +7,16 @@
This macro converts any csv to follow the convention of a windows excel file,
applying CRLF line endings and converting embedded cr and crlf to lf.
usage:
Usage:
fileref mycsv "/path/your/csv";
%mp_cleancsv(in=mycsv,out=/path/new.csv)
@param in= provide path or fileref to input csv
@param out= output path or fileref to output csv
@param qchar= quote char - hex code 22 is the double quote.
@param in= (NOTPROVIDED) Provide path or fileref to input csv. If a period is
found, it is assumed to be a file.
@param out= (NOTPROVIDED) Output path or fileref to output csv. If a period
is found, it is assumed to be a file.
@param qchar= ('22'x) Quote char - hex code 22 is the double quote.
@version 9.2
@author Allan Bowe
@@ -56,9 +58,14 @@
else do;
/* outside a quote, change cr and lf to crlf */
if inchar='0D'x then do;
crblank:
put '0D0A'x;
input inchar $char1.;
if inchar ne '0A'x then do;
if inchar='0D'x then do;
/* multiple CR indicates CR formatted file with blank lines */
goto crblank;
end;
else if inchar ne '0A'x then do;
put inchar $char1.;
if inchar=qchar then isq = mod(isq+1,2);
end;

View File

@@ -17,7 +17,7 @@
<h4> SAS Macros </h4>
@li mf_existds.sas
<h4> Related Macros <h4>
<h4> Related Macros </h4>
@li mp_jsonout.sas
@version 9.2

View File

@@ -92,7 +92,8 @@ data &outds;
/*length GROUP_LOGIC SUBGROUP_LOGIC $3 SUBGROUP_ID 8 VARIABLE_NM $32
OPERATOR_NM $10 RAW_VALUE $4000;*/
set &inds;
length reason_cd $4032 vtype $1 vnum dsid 8;
length reason_cd $4032 vtype $1 vnum dsid 8 tmp $4000;
drop tmp;
/* quick check to ensure column exists */
if upcase(VARIABLE_NM) not in
@@ -168,18 +169,32 @@ data &outds;
end;
/* special logic */
if OPERATOR_NM='BETWEEN' then raw_value1=tranwrd(raw_value,' AND ','');
else if OPERATOR_NM in ('IN','NOT IN') then do;
if substr(raw_value,1,1) ne '('
or substr(cats(reverse(raw_value)),1,1) ne ')'
then do;
REASON_CD='Missing start/end bracket in RAW_VALUE';
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
if OPERATOR_NM in ('IN','NOT IN','BETWEEN') then do;
if OPERATOR_NM='BETWEEN' then raw_value1=tranwrd(raw_value,' AND ',',');
else do;
if substr(raw_value,1,1) ne '('
or substr(cats(reverse(raw_value)),1,1) ne ')'
then do;
REASON_CD='Missing start/end bracket in RAW_VALUE';
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
end;
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
end;
/* we now have a comma seperated list of values */
if vtype='N' then do i=1 to countc(raw_value1, ',')+1;
tmp=scan(raw_value1,i,',');
if cats(tmp) ne '.' and input(tmp, ?? 8.) eq . then do;
REASON_CD='Non Numeric value provided';
putlog REASON_CD= OPERATOR_NM= raw_value= raw_value1= ;
call symputx('reason_cd',reason_cd,'l');
call symputx('nobs',_n_,'l');
output;
end;
return;
end;
else raw_value1=substr(raw_value,2,max(length(raw_value)-2,0));
end;
else raw_value1=raw_value;

View File

@@ -94,8 +94,11 @@ create table &outds as
/**
* We cannot apply this clause to the underlying dictionary table. See:
* https://communities.sas.com/t5/SAS-Programming/Unexpected-Where-Clause-behaviour-in-dictionary-TABLE/m-p/771554#M244867
* cannot use`where calculated libref="&lib"` either as it will STILL execute
* all the underlying constraint queries, causing exception errors in some
* cases: https://github.com/sasjs/core/issues/283
*/
where calculated libref="&lib"
where a.TABLE_CATALOG="&lib"
%if "&ds" ne "" %then %do;
and upcase(a.TABLE_NAME)="&ds"
and upcase(b.TABLE_NAME)="&ds"

View File

@@ -130,13 +130,13 @@ run;
%local x curds;
%if &flavour=SAS %then %do;
data _null_;
file &fref mod;
put "/* SAS Flavour DDL for %upcase(&libref).&curds */";
put "proc sql;";
run;
%do x=1 %to %sysfunc(countw(&dsnlist));
%let curds=%scan(&dsnlist,&x);
data _null_;
file &fref mod;
put "/* SAS Flavour DDL for %upcase(&libref).&curds */";
put "proc sql;";
run;
data _null_;
file &fref mod;
length lab $1024 typ $20;

View File

@@ -34,6 +34,7 @@
@param [out] outds= (work.mp_getpk) The name of the output table to create.
<h4> SAS Macros </h4>
@li mf_existfeature.sas
@li mf_getengine.sas
@li mf_getschema.sas
@li mp_dropmembers.sas
@@ -229,7 +230,12 @@ create table work.&tabs1 as select
libname as libref
,upcase(memname) as dsn
,memtype
%if %mf_existfeature(DBMS_MEMTYPE)=1 %then %do;
,dbms_memtype
%end;
%else %do;
,'n/a' as dbms_memtype format=$32.
%end;
,typemem
,memlabel
,nvar

View File

@@ -62,7 +62,7 @@
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
that should be converted to JSON
<h4> Related Macros <h4>
<h4> Related Macros </h4>
@li mp_ds2fmtds.sas
@version 9.2
@@ -70,14 +70,13 @@
@source https://github.com/sasjs/core
**/
%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y
,engine=DATASTEP
,missing=NULL
,showmeta=N
,maxobs=MAX
)/*/STORE SOURCE*/;
%local tempds colinfo fmtds i numcols stmt_obs;
%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval;
%let numcols=0;
%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;);
@@ -126,7 +125,6 @@
if format='' then fmt=cats('$',length,'.');
else if formatl=0 then fmt=cats(format,'.');
else fmt=cats(format,formatl,'.');
newlen=max(formatl,length);
end;
else do;
typelong='num';
@@ -134,16 +132,17 @@
else if formatl=0 then fmt=cats(format,'.');
else if formatd=0 then fmt=cats(format,formatl,'.');
else fmt=cats(format,formatl,'.',formatd);
/* needs to be wide, for datetimes etc */
newlen=max(length,formatl,24);
end;
/* 32 char unique name */
newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27);
maxlenv='maxlen'!!substr(cats(put(md5(name),$hex32.)),1,26);
call symputx(cats('name',_n_),name,'l');
call symputx(cats('newname',_n_),newname,'l');
call symputx(cats('len',_n_),newlen,'l');
call symputx(cats('maxlenv',_n_),maxlenv,'l');
call symputx(cats('length',_n_),length,'l');
/* overwritten when fmt=Y */
call symputx(cats('fmtlen',_n_),min(32767,ceil((length+3)*1.2)),'l');
call symputx(cats('fmt',_n_),fmt,'l');
call symputx(cats('type',_n_),type,'l');
call symputx(cats('typelong',_n_),typelong,'l');
@@ -151,6 +150,9 @@
run;
%let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
proc sql;
select count(*) into: lastobs from &ds;
%if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs));
%if &engine=PROCJSON %then %do;
%if &missing=STRING %then %do;
@@ -187,23 +189,49 @@
%end;
%if &fmt=Y %then %do;
data _data_;
%let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32);
/* need to find max length of formatted values */
data _data_(compress=char);
/* rename on entry */
set &ds(rename=(
%do i=1 %to &numcols;
&&name&i=&&newname&i
%end;
));
&stmt_obs;
/* formatted values can be up to length 32767 */
length
%do i=1 %to &numcols;
&&name&i
%end;
$32767;
retain &tempvar
%do i=1 %to &numcols;
&&maxlenv&i
%end;
0;
drop &tempvar
%do i=1 %to &numcols;
&&newname&i &&maxlenv&i
%end;
;
%do i=1 %to &numcols;
length &&name&i $&&len&i;
%if &&typelong&i=num %then %do;
&&name&i=left(put(&&newname&i,&&fmt&i));
&&name&i=cats(put(&&newname&i,&&fmt&i));
%end;
%else %do;
&&name&i=put(&&newname&i,&&fmt&i);
%end;
drop &&newname&i;
/* grab max length of each value as we move down the data step */
&tempvar=length(&&name&i);
if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar;
%end;
if _n_=&lastobs then do;
/* add a 20% buffer in case of special chars that need to be escaped */
%do i=1 %to &numcols;
call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),'l');
%end;
end;
if _error_ then call symputx('syscc',1012);
run;
%let fmtds=&syslast;
@@ -221,12 +249,15 @@
%end;
other = [best.];
/* configure varlenchk - as we are explicitly shortening the variables */
%let optval=%sysfunc(getoption(varlenchk));
options varlenchk=NOWARN;
data &tempds;
attrib _all_ label='';
%do i=1 %to &numcols;
%if &&typelong&i=char or &fmt=Y %then %do;
length &&name&i $32767;
format &&name&i $32767.;
length &&name&i $&&fmtlen&i...;
format &&name&i $&&fmtlen&i...;
%end;
%end;
%if &fmt=Y %then %do;
@@ -259,6 +290,7 @@
%end;
%end;
run;
options varlenchk=&optval;
filename _sjs3 temp lrecl=131068 ;
data _null_;
@@ -296,6 +328,7 @@
filename _sjs4 temp lrecl=131068 encoding='utf-8';
data _null_;
file _sjs4;
length label $350;
put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{";
do i=1 to &numcols;
name=quote(trim(symget(cats('name',i))));

View File

@@ -1,13 +1,14 @@
/**
@file
@brief Logs the time the macro was executed in a control dataset.
@details If the dataset does not exist, it is created. Usage:
@brief Logs a message in a dataset every time it is invoked
@details If the dataset does not exist, it is created.
Usage:
%mp_perflog(started)
%mp_perflog()
%mp_perflog(startanew,libds=work.newdataset)
%mp_perflog(finished,libds=work.newdataset)
%mp_perflog(finished)
%mp_perflog(started)
%mp_perflog()
%mp_perflog(startanew,libds=work.newdataset)
%mp_perflog(finished,libds=work.newdataset)
%mp_perflog(finished)
@param label Provide label to go into the control dataset

View File

@@ -154,7 +154,9 @@ run;
%else %let vlist=%mf_getvarlist(&libds,dlm=%str(,),quote=DOUBLE);
data &ds4;
length &inds_keep $41 tgtvar_nm $32;
length &inds_keep $41 tgtvar_nm $32 _label_ $256;
if _n_=1 then call missing(_label_);
drop _label_;
set &ds2 &ds3 indsname=&inds_auto;
tgtvar_nm=upcase(tgtvar_nm);

View File

@@ -93,14 +93,13 @@ data _null_;
file sasjs lrecl=3000 ;
put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
/* WEBOUT BEGIN */
put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y ';
put ' ,engine=DATASTEP ';
put ' ,missing=NULL ';
put ' ,showmeta=N ';
put ' ,maxobs=MAX ';
put ')/*/STORE SOURCE*/; ';
put '%local tempds colinfo fmtds i numcols stmt_obs; ';
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
put '%let numcols=0; ';
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
put ' ';
@@ -149,7 +148,6 @@ data _null_;
put ' if format='''' then fmt=cats(''$'',length,''.''); ';
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else fmt=cats(format,formatl,''.''); ';
put ' newlen=max(formatl,length); ';
put ' end; ';
put ' else do; ';
put ' typelong=''num''; ';
@@ -157,16 +155,17 @@ data _null_;
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
put ' else fmt=cats(format,formatl,''.'',formatd); ';
put ' /* needs to be wide, for datetimes etc */ ';
put ' newlen=max(length,formatl,24); ';
put ' end; ';
put ' /* 32 char unique name */ ';
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
put ' ';
put ' call symputx(cats(''name'',_n_),name,''l''); ';
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
put ' call symputx(cats(''length'',_n_),length,''l''); ';
put ' /* overwritten when fmt=Y */ ';
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
@@ -174,6 +173,9 @@ data _null_;
put ' run; ';
put ' ';
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql; ';
put ' select count(*) into: lastobs from &ds; ';
put ' %if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs)); ';
put ' ';
put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
@@ -210,23 +212,49 @@ data _null_;
put ' %end; ';
put ' ';
put ' %if &fmt=Y %then %do; ';
put ' data _data_; ';
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' /* need to find max length of formatted values */ ';
put ' data _data_(compress=char); ';
put ' /* rename on entry */ ';
put ' set &ds(rename=( ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i=&&newname&i ';
put ' %end; ';
put ' )); ';
put ' &stmt_obs; ';
put ' /* formatted values can be up to length 32767 */ ';
put ' length ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i ';
put ' %end; ';
put ' $32767; ';
put ' retain &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&maxlenv&i ';
put ' %end; ';
put ' 0; ';
put ' drop &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&newname&i &&maxlenv&i ';
put ' %end; ';
put ' ; ';
put ' %do i=1 %to &numcols; ';
put ' length &&name&i $&&len&i; ';
put ' %if &&typelong&i=num %then %do; ';
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
put ' &&name&i=cats(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 ' /* grab max length of each value as we move down the data step */ ';
put ' &tempvar=length(&&name&i); ';
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
put ' %end; ';
put ' if _n_=&lastobs then do; ';
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
put ' %do i=1 %to &numcols; ';
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
put ' %end; ';
put ' end; ';
put ' if _error_ then call symputx(''syscc'',1012); ';
put ' run; ';
put ' %let fmtds=&syslast; ';
@@ -244,12 +272,15 @@ data _null_;
put ' %end; ';
put ' other = [best.]; ';
put ' ';
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
put ' options varlenchk=NOWARN; ';
put ' data &tempds; ';
put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' length &&name&i $32767; ';
put ' format &&name&i $32767.; ';
put ' length &&name&i $&&fmtlen&i...; ';
put ' format &&name&i $&&fmtlen&i...; ';
put ' %end; ';
put ' %end; ';
put ' %if &fmt=Y %then %do; ';
@@ -282,6 +313,7 @@ data _null_;
put ' %end; ';
put ' %end; ';
put ' run; ';
put ' options varlenchk=&optval; ';
put ' ';
put ' filename _sjs3 temp lrecl=131068 ; ';
put ' data _null_; ';
@@ -319,6 +351,7 @@ data _null_;
put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' length label $350; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -371,7 +404,7 @@ data _null_;
put ' ';
put '%mend mf_getuser; ';
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
put ' ,showmeta=N ';
put ' ,showmeta=N,maxobs=MAX ';
put '); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; ';
@@ -438,7 +471,7 @@ data _null_;
put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=&jsonengine,missing=&missing,showmeta=&showmeta ';
put ' ,engine=&jsonengine,missing=&missing,showmeta=&showmeta,maxobs=&maxobs ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -479,26 +512,33 @@ data _null_;
put ' %end; ';
put ' /* close off json */ ';
put ' data _null_;file _sjsref mod encoding=''utf-8''; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' length SYSPROCESSNAME syserrortext syswarningtext autoexec $512; ';
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' _METAUSER=quote(trim(symget(''_METAUSER''))); ';
put ' put ",""_METAUSER"": " _METAUSER; ';
put ' _METAPERSON=quote(trim(symget(''_METAPERSON''))); ';
put ' put '',"_METAPERSON": '' _METAPERSON; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
put ' put '',"AUTOEXEC" : '' autoexec; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
put ' put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" "; ';
put ' SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME))); ';
put ' put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';

View File

@@ -34,7 +34,8 @@
such as the column formats and types. The metadata is contained inside an
object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
that should be converted to output JSON
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@@ -44,7 +45,7 @@
**/
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL
,showmeta=N
,showmeta=N,maxobs=MAX
);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables;
@@ -111,7 +112,7 @@
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=&jsonengine,missing=&missing,showmeta=&showmeta
,engine=&jsonengine,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
)
%end;
%else %if &action=CLOSE %then %do;
@@ -152,26 +153,33 @@
%end;
/* close off json */
data _null_;file _sjsref mod encoding='utf-8';
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
put ",""_DEBUG"" : ""&_debug"" ";
_METAUSER=quote(trim(symget('_METAUSER')));
put ",""_METAUSER"": " _METAUSER;
_METAPERSON=quote(trim(symget('_METAPERSON')));
put ',"_METAPERSON": ' _METAPERSON;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
autoexec=quote(urlencode(trim(getoption('autoexec'))));
put ',"AUTOEXEC" : ' autoexec;
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=quote(cats(symget('SYSERRORTEXT')));
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;

View File

@@ -0,0 +1,50 @@
/**
@file
@brief Creates a metadata folder
@details Creates a metadata folder using the batch tools
Usage:
%mmx_createmetafolder(loc=/some/meta/folder,user=sasdemo,pass=mars345)
<h4> SAS Macros </h4>
@li mf_loc.sas
@li mp_abort.sas
@param loc= the metadata folder to delete
@param user= username
@param pass= password
@version 9.4
@author Allan Bowe
**/
%macro mmx_createmetafolder(loc=,user=,pass=);
%local host port path connx_string msg;
%let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport));
%let path=%mf_loc(POF)/tools;
%let connx_string= -host &host -port &port -user '&user' -password '&pass';
/* remove directory */
data _null_;
infile " &path/sas-make-folder &connx_string ""&loc"" -makeFullPath 2>&1"
pipe lrecl=10000;
input;
putlog _infile_;
run;
data _null_; /* check tree exists */
length type uri $256;
rc=metadata_pathobj("","&loc","Folder",type,uri);
call symputx('foldertype',type,'l');
run;
%let msg=Location (&loc) was not created!!;
%mp_abort(iftrue= (&foldertype ne Tree)
,mac=&_program..sas
,msg=%superq(msg)
)
%mend mmx_createmetafolder;

View File

@@ -7,7 +7,7 @@
Usage:
%mmx_deletemetafolder(loc=/some/meta/folder,user=sasdemo,pass=mars345)
%mmx_deletemetafolder(loc=/some/meta/folder,user=sasdemo,pass=mars345)
<h4> SAS Macros </h4>
@li mf_loc.sas
@@ -37,4 +37,4 @@ data _null_;
putlog _infile_;
run;
%mend mmx_deletemetafolder;
%mend mmx_deletemetafolder;

View File

@@ -25,6 +25,21 @@
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
$extrastylesheet
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = "https://analytics.4gl.io/";
_paq.push(['setTrackerUrl', u + 'matomo.php']);
_paq.push(['setSiteId', '6']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
@@ -68,4 +83,4 @@
</div>
</body>
</html>
</html>

View File

@@ -67,7 +67,7 @@
},
{
"name": "server",
"serverUrl": "",
"serverUrl": "https://sas.4gl.io",
"serverType": "SASJS",
"httpsAgentOptions": {
"allowInsecureRequests": false
@@ -107,4 +107,4 @@
"contextName": "SAS Job Execution compute context"
}
]
}
}

View File

@@ -94,14 +94,13 @@ data _null_;
file &sasjsref termstr=crlf lrecl=512;
put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
/* WEBOUT BEGIN */
put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y ';
put ' ,engine=DATASTEP ';
put ' ,missing=NULL ';
put ' ,showmeta=N ';
put ' ,maxobs=MAX ';
put ')/*/STORE SOURCE*/; ';
put '%local tempds colinfo fmtds i numcols stmt_obs; ';
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
put '%let numcols=0; ';
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
put ' ';
@@ -150,7 +149,6 @@ data _null_;
put ' if format='''' then fmt=cats(''$'',length,''.''); ';
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else fmt=cats(format,formatl,''.''); ';
put ' newlen=max(formatl,length); ';
put ' end; ';
put ' else do; ';
put ' typelong=''num''; ';
@@ -158,16 +156,17 @@ data _null_;
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
put ' else fmt=cats(format,formatl,''.'',formatd); ';
put ' /* needs to be wide, for datetimes etc */ ';
put ' newlen=max(length,formatl,24); ';
put ' end; ';
put ' /* 32 char unique name */ ';
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
put ' ';
put ' call symputx(cats(''name'',_n_),name,''l''); ';
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
put ' call symputx(cats(''length'',_n_),length,''l''); ';
put ' /* overwritten when fmt=Y */ ';
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
@@ -175,6 +174,9 @@ data _null_;
put ' run; ';
put ' ';
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql; ';
put ' select count(*) into: lastobs from &ds; ';
put ' %if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs)); ';
put ' ';
put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
@@ -211,23 +213,49 @@ data _null_;
put ' %end; ';
put ' ';
put ' %if &fmt=Y %then %do; ';
put ' data _data_; ';
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' /* need to find max length of formatted values */ ';
put ' data _data_(compress=char); ';
put ' /* rename on entry */ ';
put ' set &ds(rename=( ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i=&&newname&i ';
put ' %end; ';
put ' )); ';
put ' &stmt_obs; ';
put ' /* formatted values can be up to length 32767 */ ';
put ' length ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i ';
put ' %end; ';
put ' $32767; ';
put ' retain &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&maxlenv&i ';
put ' %end; ';
put ' 0; ';
put ' drop &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&newname&i &&maxlenv&i ';
put ' %end; ';
put ' ; ';
put ' %do i=1 %to &numcols; ';
put ' length &&name&i $&&len&i; ';
put ' %if &&typelong&i=num %then %do; ';
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
put ' &&name&i=cats(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 ' /* grab max length of each value as we move down the data step */ ';
put ' &tempvar=length(&&name&i); ';
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
put ' %end; ';
put ' if _n_=&lastobs then do; ';
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
put ' %do i=1 %to &numcols; ';
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
put ' %end; ';
put ' end; ';
put ' if _error_ then call symputx(''syscc'',1012); ';
put ' run; ';
put ' %let fmtds=&syslast; ';
@@ -245,12 +273,15 @@ data _null_;
put ' %end; ';
put ' other = [best.]; ';
put ' ';
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
put ' options varlenchk=NOWARN; ';
put ' data &tempds; ';
put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' length &&name&i $32767; ';
put ' format &&name&i $32767.; ';
put ' length &&name&i $&&fmtlen&i...; ';
put ' format &&name&i $&&fmtlen&i...; ';
put ' %end; ';
put ' %end; ';
put ' %if &fmt=Y %then %do; ';
@@ -283,6 +314,7 @@ data _null_;
put ' %end; ';
put ' %end; ';
put ' run; ';
put ' options varlenchk=&optval; ';
put ' ';
put ' filename _sjs3 temp lrecl=131068 ; ';
put ' data _null_; ';
@@ -320,6 +352,7 @@ data _null_;
put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' length label $350; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -373,7 +406,7 @@ data _null_;
put '%mend mf_getuser; ';
put ' ';
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
put ' ,showmeta=N ';
put ' ,showmeta=N,maxobs=MAX ';
put '); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; ';
@@ -432,7 +465,7 @@ data _null_;
put ' %let missing=NULL; ';
put ' %end; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -472,35 +505,34 @@ data _null_;
put ' %end; ';
put ' /* close off json */ ';
put ' data _null_;file &fref mod encoding=''utf-8'' termstr=lf lrecl=32767; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' length SYSPROCESSNAME syserrortext syswarningtext autoexec $512; ';
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
put ' put '',"AUTOEXEC" : '' autoexec; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); ';
put ' put '',"SYSHOSTINFOLONG" : '' SYSHOSTINFOLONG; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
put ' put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" "; ';
put ' length SYSPROCESSNAME $512; ';
put ' SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME))); ';
put ' put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" "; ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length autoexec $512; ';
put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
put ' put '',"AUTOEXEC" : '' autoexec; ';
put ' length memsize $32; ';
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
put ' memsize=quote(cats(memsize)); ';

View File

@@ -116,14 +116,16 @@ libname &libref JSON fileref=&fref1;
%if "&group"="0" and "&gid"="0" %then %do;
data &outds;
length DISPLAYNAME $60 USERNAME:$30 ID 8;
set &libref..root;
if nobs=0 then call missing(of _all_);
set &libref..root nobs=nobs;
drop ordinal_root;
run;
%end;
%else %do;
data &outds;
length DISPLAYNAME $60 USERNAME:$30 ID 8;
set &libref..users;
if nobs=0 then call missing(of _all_);
set &libref..users nobs=nobs;
drop ordinal_root ordinal_users;
run;
%end;

View File

@@ -31,6 +31,8 @@
such as the column formats and types. The metadata is contained inside an
object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
that should be converted to output JSON
<h4> SAS Macros </h4>
@li mf_getuser.sas
@@ -47,7 +49,7 @@
**/
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL
,showmeta=N
,showmeta=N,maxobs=MAX
);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables;
@@ -106,7 +108,7 @@
%let missing=NULL;
%end;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,missing=&missing,showmeta=&showmeta
,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
)
%end;
%else %if &action=CLOSE %then %do;
@@ -146,35 +148,34 @@
%end;
/* close off json */
data _null_;file &fref mod encoding='utf-8' termstr=lf lrecl=32767;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" ";
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
put ",""_DEBUG"" : ""&_debug"" ";
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
autoexec=quote(urlencode(trim(getoption('autoexec'))));
put ',"AUTOEXEC" : ' autoexec;
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=quote(cats(symget('SYSERRORTEXT')));
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
length SYSPROCESSNAME $512;
SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length autoexec $512;
autoexec=quote(urlencode(trim(getoption('autoexec'))));
put ',"AUTOEXEC" : ' autoexec;
length memsize $32;
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
memsize=quote(cats(memsize));

View File

@@ -0,0 +1,35 @@
/**
@file
@brief Testing mf_increment macro
<h4> SAS Macros </h4>
@li mf_increment.sas
@li mp_assert.sas
**/
%let var=0;
%mp_assert(
iftrue=(
"%mf_increment(var)"="1"
),
desc=Checking basic mf_increment usage 1,
outds=work.test_results
)
%mp_assert(
iftrue=(
"%mf_increment(var)"="2"
),
desc=Checking basic mf_increment usage 2,
outds=work.test_results
)
%mp_assert(
iftrue=(
"%mf_increment(var,incr=2)"="4"
),
desc=Checking incr option,
outds=work.test_results
)

View File

@@ -0,0 +1,43 @@
/**
@file
@brief Testing mp_cleancsv.sas macro
@details Credit for test 1 goes to
[Tom](https://communities.sas.com/t5/user/viewprofilepage/user-id/159) from
SAS Communities:
https://communities.sas.com/t5/SAS-Programming/Removing-embedded-carriage-returns/m-p/824790#M325761
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_cleancsv.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* test 1 - cope with empty rows on CR formatted file */
filename crlf "%sysfunc(pathname(work))/crlf";
filename cr "%sysfunc(pathname(work))/cr";
data _null_;
file cr termstr=cr ;
put 'line 1'///'line 4'/'line 5';
run;
%mp_assertscope(SNAPSHOT)
%mp_cleancsv(in=cr,out=crlf)
%mp_assertscope(COMPARE)
/* 5 rows as all converted to OD0A */
data test1;
infile "%sysfunc(pathname(work))/crlf" lrecl=100 termstr=crlf;
input;
list;
run;
%put test1=%mf_nobs(test1);
%mp_assert(
iftrue=(%mf_nobs(work.test1)=5),
desc=Checking blank rows on CR formatted file,
outds=work.test_results
)

View File

@@ -38,7 +38,7 @@ William,M,15,66.5,112
;;;;
run;
/* valid filter conditions */
/* VALID filter conditions */
data work.inds;
infile datalines4 dsd;
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
@@ -51,6 +51,9 @@ AND,OR,2,Weight,>=,77.7
AND,OR,2,Weight,NE,77.7
AND,AND,1,age,=,.A
AND,AND,1,height,<,.B
AND,AND,1,age,IN,"(.a,.b,.)"
AND,AND,1,age,IN,"(.A)"
;;;;
run;
@@ -115,6 +118,28 @@ run;
outds=work.test_results
)
/* invalid IN value */
data work.inds;
infile datalines4 dsd;
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
OPERATOR_NM:$10. RAW_VALUE:$4000.;
datalines4;
AND,OR,2,age,IN,"(.,.a,X)"
;;;;
run;
%mp_filtercheck(work.inds,
targetds=work.class,
outds=work.badrecords,
abort=NO
)
%let syscc=0;
%mp_assertdsobs(work.badrecords,
desc=Invalid IN value,
test=HASOBS,
outds=work.test_results
)
/* Code injection - column name */
data work.inds;
infile datalines4 dsd;
@@ -163,7 +188,7 @@ run;
data work.inds;
infile datalines4 dsd;
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
OPERATOR_NM:$10. RAW_VALUE:8;
OPERATOR_NM:$10. RAW_VALUE:8.;
datalines4;
AND,AND,1,age,=,0
;;;;

View File

@@ -56,6 +56,9 @@ AND,AND,1,SEX,<=,"'M'"
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
AND,OR,2,Weight,>=,77.7
AND,OR,2,Weight,NE,77.7
AND,AND,3,age,NOT IN,"(.a,.b,.)"
AND,AND,3,age,NOT IN,"(.A)"
AND,AND,4,Name,=,"'Jeremiah'"
;;;;
run;

View File

@@ -236,14 +236,13 @@ data _null_;
file &adapter;
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
/* WEBOUT BEGIN */
put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y ';
put ' ,engine=DATASTEP ';
put ' ,missing=NULL ';
put ' ,showmeta=N ';
put ' ,maxobs=MAX ';
put ')/*/STORE SOURCE*/; ';
put '%local tempds colinfo fmtds i numcols stmt_obs; ';
put '%local tempds colinfo fmtds i numcols stmt_obs tempvar lastobs optval; ';
put '%let numcols=0; ';
put '%if &maxobs ne MAX %then %let stmt_obs=%str(if _n_>&maxobs then stop;); ';
put ' ';
@@ -292,7 +291,6 @@ data _null_;
put ' if format='''' then fmt=cats(''$'',length,''.''); ';
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else fmt=cats(format,formatl,''.''); ';
put ' newlen=max(formatl,length); ';
put ' end; ';
put ' else do; ';
put ' typelong=''num''; ';
@@ -300,16 +298,17 @@ data _null_;
put ' else if formatl=0 then fmt=cats(format,''.''); ';
put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
put ' else fmt=cats(format,formatl,''.'',formatd); ';
put ' /* needs to be wide, for datetimes etc */ ';
put ' newlen=max(length,formatl,24); ';
put ' end; ';
put ' /* 32 char unique name */ ';
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
put ' maxlenv=''maxlen''!!substr(cats(put(md5(name),$hex32.)),1,26); ';
put ' ';
put ' call symputx(cats(''name'',_n_),name,''l''); ';
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''maxlenv'',_n_),maxlenv,''l''); ';
put ' call symputx(cats(''length'',_n_),length,''l''); ';
put ' /* overwritten when fmt=Y */ ';
put ' call symputx(cats(''fmtlen'',_n_),min(32767,ceil((length+3)*1.2)),''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
@@ -317,6 +316,9 @@ data _null_;
put ' run; ';
put ' ';
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' proc sql; ';
put ' select count(*) into: lastobs from &ds; ';
put ' %if &maxobs ne MAX %then %let lastobs=%sysfunc(min(&lastobs,&maxobs)); ';
put ' ';
put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
@@ -353,23 +355,49 @@ data _null_;
put ' %end; ';
put ' ';
put ' %if &fmt=Y %then %do; ';
put ' data _data_; ';
put ' %let tempvar=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
put ' /* need to find max length of formatted values */ ';
put ' data _data_(compress=char); ';
put ' /* rename on entry */ ';
put ' set &ds(rename=( ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i=&&newname&i ';
put ' %end; ';
put ' )); ';
put ' &stmt_obs; ';
put ' /* formatted values can be up to length 32767 */ ';
put ' length ';
put ' %do i=1 %to &numcols; ';
put ' &&name&i ';
put ' %end; ';
put ' $32767; ';
put ' retain &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&maxlenv&i ';
put ' %end; ';
put ' 0; ';
put ' drop &tempvar ';
put ' %do i=1 %to &numcols; ';
put ' &&newname&i &&maxlenv&i ';
put ' %end; ';
put ' ; ';
put ' %do i=1 %to &numcols; ';
put ' length &&name&i $&&len&i; ';
put ' %if &&typelong&i=num %then %do; ';
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
put ' &&name&i=cats(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 ' /* grab max length of each value as we move down the data step */ ';
put ' &tempvar=length(&&name&i); ';
put ' if &tempvar>&&maxlenv&i then &&maxlenv&i=&tempvar; ';
put ' %end; ';
put ' if _n_=&lastobs then do; ';
put ' /* add a 20% buffer in case of special chars that need to be escaped */ ';
put ' %do i=1 %to &numcols; ';
put ' call symputx("fmtlen&i",min(32767,ceil((&&maxlenv&i+3)*1.2)),''l''); ';
put ' %end; ';
put ' end; ';
put ' if _error_ then call symputx(''syscc'',1012); ';
put ' run; ';
put ' %let fmtds=&syslast; ';
@@ -387,12 +415,15 @@ data _null_;
put ' %end; ';
put ' other = [best.]; ';
put ' ';
put ' /* configure varlenchk - as we are explicitly shortening the variables */ ';
put ' %let optval=%sysfunc(getoption(varlenchk)); ';
put ' options varlenchk=NOWARN; ';
put ' data &tempds; ';
put ' attrib _all_ label=''''; ';
put ' %do i=1 %to &numcols; ';
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
put ' length &&name&i $32767; ';
put ' format &&name&i $32767.; ';
put ' length &&name&i $&&fmtlen&i...; ';
put ' format &&name&i $&&fmtlen&i...; ';
put ' %end; ';
put ' %end; ';
put ' %if &fmt=Y %then %do; ';
@@ -425,6 +456,7 @@ data _null_;
put ' %end; ';
put ' %end; ';
put ' run; ';
put ' options varlenchk=&optval; ';
put ' ';
put ' filename _sjs3 temp lrecl=131068 ; ';
put ' data _null_; ';
@@ -462,6 +494,7 @@ data _null_;
put ' filename _sjs4 temp lrecl=131068 encoding=''utf-8''; ';
put ' data _null_; ';
put ' file _sjs4; ';
put ' length label $350; ';
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
put ' do i=1 to &numcols; ';
put ' name=quote(trim(symget(cats(''name'',i)))); ';
@@ -514,7 +547,7 @@ data _null_;
put ' ';
put '%mend mf_getuser; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL ';
put ' ,showmeta=N ';
put ' ,showmeta=N,maxobs=MAX ';
put '); ';
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
put ' sasjs_tables SYS_JES_JOB_URI; ';
@@ -616,8 +649,8 @@ data _null_;
put ' run; ';
put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -653,23 +686,31 @@ data _null_;
put ' ';
put ' /* close off json */ ';
put ' data _null_;file &fref mod; ';
put ' length SYSPROCESSNAME syserrortext syswarningtext autoexec $512; ';
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
put ' put '',"AUTOEXEC" : '' autoexec; ';
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' SYS_JES_JOB_URI=quote(trim(resolve(symget(''SYS_JES_JOB_URI'')))); ';
put ' put '',"SYS_JES_JOB_URI" : '' SYS_JES_JOB_URI ; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
put ' put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" "; ';
put ' SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME))); ';
put ' put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';

View File

@@ -33,6 +33,8 @@
such as the column formats and types. The metadata is contained inside an
object with the same name as the table but prefixed with a dollar sign - ie,
`,"$tablename":{"formats":{"col1":"$CHAR1"},"types":{"COL1":"C"}}`
@param [in] maxobs= (MAX) Provide an integer to limit the number of input rows
that should be converted to output JSON
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@@ -43,7 +45,7 @@
**/
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL
,showmeta=N
,showmeta=N,maxobs=MAX
);
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
sasjs_tables SYS_JES_JOB_URI;
@@ -145,8 +147,8 @@
run;
%end;
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
,jref=&fref,engine=DATASTEP,missing=&missing,showmeta=&showmeta
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,missing=&missing,showmeta=&showmeta,maxobs=&maxobs
)
%end;
%else %if &action=CLOSE %then %do;
@@ -182,23 +184,31 @@
/* close off json */
data _null_;file &fref mod;
length SYSPROCESSNAME syserrortext syswarningtext autoexec $512;
put ",""_DEBUG"" : ""&_debug"" ";
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ",""SYSUSERID"" : ""&sysuserid"" ";
put ',"_PROGRAM" : ' _PROGRAM ;
autoexec=quote(urlencode(trim(getoption('autoexec'))));
put ',"AUTOEXEC" : ' autoexec;
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
SYS_JES_JOB_URI=quote(trim(resolve(symget('SYS_JES_JOB_URI'))));
put ',"SYS_JES_JOB_URI" : ' SYS_JES_JOB_URI ;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""_DEBUG"" : ""&_debug"" ";
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=quote(cats(symget('SYSERRORTEXT')));
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" ";
SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME)));
put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;