diff --git a/all.sas b/all.sas index bbbd3c5..0b9befd 100644 --- a/all.sas +++ b/all.sas @@ -4612,7 +4612,7 @@ data &outds(keep=name type length varnum format label ddtype); else if formatd=0 then format=cats(format2,formatl,'.'); else format=cats(format2,formatl,'.',formatd); type='N'; - if format=:'DATETIME' then ddtype='DATETIME'; + if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME'; else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY' or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA' or format=:'MONYY' @@ -6325,6 +6325,59 @@ run; filename &tempref clear; %mend mp_include;/** + @file + @brief Initialise session with useful settings and variables + @details Implements a set of recommended options for general SAS use. This + macro is NOT used elsewhere within the core library (other than in tests), + but it is used by the SASjs team when building web services for + SAS-Powered applications elsewhere. + + If you have a good idea for an option, setting, or useful global variable - + feel free to [raise an issue](https://github.com/sasjs/core/issues/new)! + + All global variables are prefixed with "SASJS_" (unless modfied with the + prefix parameter). + + @param [in] prefix= (SASJS) The prefix to apply to the global macro variables + + + @version 9.2 + @author Allan Bowe + +**/ + +%macro mp_init(prefix= +)/*/STORE SOURCE*/; + + %global + &prefix._INIT_NUM /* initialisation time as numeric */ + &prefix._INIT_DTTM /* initialisation time in E8601DT26.6 format */ + ; + %if %eval(&&&prefix._INIT_NUM>0) %then %return; /* only run once */ + + data _null_; + dttm=datetime(); + call symputx("&prefix._init_num",dttm); + call symputx("&prefix._init_dttm",put(dttm,E8601DT26.6)); + run; + + options + autocorrect /* disallow mis-spelled procedure names */ + compress=CHAR /* default is none so ensure we have something! */ + datastmtchk=ALLKEYWORDS /* protection from overwriting input datasets */ + errorcheck=STRICT /* catch errors in libname/filename statements */ + fmterr /* ensure error when a format cannot be found */ + mergenoby=ERROR /* + missing=. /* some sites change this which causes hard to detect errors */ + noquotelenmax /* avoid warnings for long strings */ + noreplace /* avoid overwriting permanent datasets */ + ps=max /* reduce log size slightly */ + validmemname=COMPATIBLE /* avoid special characters etc in table names */ + validvarname=V7 /* avoid special characters etc in variable names */ + varlenchk=ERROR /* fail hard if truncation (data loss) can result */ + ; + +%mend mp_init;/** @file mp_jsonout.sas @brief Writes JSON in SASjs format to a fileref @details PROC JSON is faster but will produce errs like the ones below if @@ -7062,6 +7115,50 @@ lock &libds clear; ) %mend mp_lockfilecheck;/** + @file + @brief Create sample data based on the structure of an empty table + @details Many SAS projects involve sensitive datasets. One way to _ensure_ + the data is anonymised, is never to receive it in the first place! Often + consultants are provided with empty tables, and expected to create complex + ETL flows. + + This macro can help by taking an empty table, and populating it with data + according to the variable types and formats. + + The primary key is respected, as well as any NOT NULL constraints. + + Usage: + + proc sql; + create table work.example( + TX_FROM float format=datetime19., + DD_TYPE char(16), + DD_SOURCE char(2048), + DD_SHORTDESC char(256), + constraint pk primary key(tx_from, dd_type,dd_source), + constraint nnn not null(DD_SHORTDESC) + ); + %mp_makedata(work.example) + + @param [in] libds The empty table in which to create data + @param [out] obs= (500) The number of records to create. + +

SAS Macros

+ @li mf_nobs.sas + @li mp_getcols.sas + @li mp_getpk.sas + + @version 9.2 + @author Allan Bowe + +**/ + +%macro mp_makedata(libds + ,obs=500 +)/*/STORE SOURCE*/; + + +%mend mp_makedata;/** @file @brief Create a Markdown Table from a dataset @details A markdown table is a simple table representation for use in @@ -7377,6 +7474,32 @@ insert into &outds select distinct * from &append_ds; %mend mp_recursivejoin; /** + @file + @brief Reset when an err condition occurs + @details When building apps, sometimes an operation must be attempted that + can cause an err condition. There is no try catch in SAS! So the err state + must be caught and reset. + + This macro attempts to do that reset. + + @version 9.2 + @author Allan Bowe + +**/ + +%macro mp_reseterror( +)/*/STORE SOURCE*/; + +options obs=max replace nosyntaxcheck; +%let syscc=0; + +%if "&sysprocessmode " = "SAS Stored Process Server " %then %do; + data _null_; + rc=stpsrvset('program error', 0); + run; +%end; + +%mend mp_reseterror;/** @file @brief Reset an option to original value @details Inspired by the SAS Jedi - diff --git a/tests/crossplatform/mp_lib2inserts.test.sas b/tests/crossplatform/mp_lib2inserts.test.sas index e28d79f..c67765f 100644 --- a/tests/crossplatform/mp_lib2inserts.test.sas +++ b/tests/crossplatform/mp_lib2inserts.test.sas @@ -11,9 +11,10 @@ **/ /* grab 20 datasets from SASHELP */ -%let path=%sysfunc(pathname(work)); +%let work=%sysfunc(pathname(work)); +%let path=&work/new; %mf_mkdir(&path) -libname sashlp "&path"; +libname sashlp "&work"; proc sql noprint; create table members as select distinct lowcase(memname) as memname @@ -31,6 +32,7 @@ run; %mp_lib2inserts(sashlp, schema=work, outref=tempref,maxobs=50) /* check if it actually runs */ +libname sashlp "&path"; options source2; %inc tempref; diff --git a/tests/crossplatform/mp_reseterror.test.sas b/tests/crossplatform/mp_reseterror.test.sas index ffee380..85ebf90 100644 --- a/tests/crossplatform/mp_reseterror.test.sas +++ b/tests/crossplatform/mp_reseterror.test.sas @@ -17,7 +17,7 @@ lock sashelp.class; %mp_reseterror() %mp_assert( - iftrue=(&success=1), - desc=Checking sashelp table cannot be locked, + iftrue=(&syscc=0), + desc=Checking error condition was fixed, outds=work.test_results )