带外信号
带外返回码比带内返回码更常见、更有用,因为以下两种情况界限分明 :一个值是有效数据和性能元数据可反映出一个错误或故障。另外,由于该返回码依然表示一个通用宏变量,该变量必须初始化和重置,因此,空白返回码表明某个过程未遇到任何警告或“运行时错误”。带外信号唯一的缺点可能是必须创建附加的宏变量以传递该返回码。
“带内信号”部分所举的带内返回码案例稍作修改即可展示带外信号。在本例中,&VARS 现在仅代表数据集中变量的数量,不再传达性能故障。因此,如果出现异常情况,&VARS依然是丢失的(而不是设置为FAILURE)。
%macrotest;
%globalvars;
%letvars=;
%globaltestrc;
%lettestrc=GENERALFAILURE;
%letdsid=%sysfunc(open(perm.final,i));
%if%sysfunc(sysrc())=0%then%do;
%letvars=%sysfunc(attrn(&dsid,nvars));
%letclose=%sysfunc(close(&dsid));
%lettestrc=;
%end;
%else%lettestrc=FAILURE;
%mend;
%test;
%putVARS:&vars;
%putTESTRC:&testrc;
带外返回码的另一个优点是当空的宏变量用于表示正常运行时,%LENGTH 宏函数将用于评估是否出现了异常情况,因为返回码的长度在正常运行情况下是“0”。
以下修改显示的是 %RUNTEST宏,它是调用子 %TEST宏的父进程。如果 %TEST是成功的,%RUNTEST会在 PERM.Final 中打印变量的数量 ;如果不成功,%TEST将在日志中打印一个错误。当然,在实际的生产软件中,异常情况处理框架不会在日志中打印信息,而是动态地改变以下程序流。
%macroruntest;
%test;
%if%length(&testrc)=0%then%putVARS:&vars;
%else%putAnexceptioncausedafailure;
%mend;
%runtest;
创建带外返回码的逻辑必须确保返回码与其所代表进程的宏变量同步。例如,在 上述代码中,&TESTRC表示 %TEST宏函数的性能,而 &TESTRC能生成 &VARS。因此,它应该与 &VARS完美同步。如果 &VARS包含一个值,&TESTRC就应该是丢失的 ;如果&VARS是丢失的,&TESTRC就应该设置为 FAILURE 或 GENERALFAILURE。
在上述%TEST宏中,如果 ATTRN函数出现异常情况或错误,那么将不会设置 &VARS,因此,它会是空白的。&TESTRC也会是空白的,因为异常情况处理仅测试 OPEN函数的故障而非 ATTRN 的故障。尽管这一故障不可能发生,但这种逻辑错误可能会造成故障,两个宏变量都是空白的。为了解决这一漏洞,可以测试ATTRN函数是否成功,或者测试 &VARS的值以验证它被有效赋值。第 6章进一步讲述返回码的成功运用。