Skip to main content

$ZTRAP

Contains the location of the current error trap handler.

Synopsis

$ZTRAP
$ZT

Description

$ZTRAP contains the location of the current error trap handler. For a description of how to code an error trap handler, refer to “Handling Errors with $ZTRAP” in the “Error Processing” chapter of Using Caché ObjectScript.

  • In a routine, $ZTRAP can reference a label within the routine or within another routine. It contains the label name and the routine name. For example, if you set $ZTRAP to the label MyHandler within the routine MyRou, the $ZTRAP special variable contains MyHandler^MyRou.

  • In a procedure, $ZTRAP must reference a label within that procedure. It contains the line offset of the label from the procedure name. For example, if you set $ZTRAP to the private label MyHandler within the procedure MyProc, the $ZTRAP special variable contains +17^MyProc.

There are three ways to set $ZTRAP:

You cannot KILL $ZTRAP; attempting to do so results in a <SYNTAX> error. To eliminate the current $ZTRAP value, specify $ZTRAP="".

Location

Using the SET command you can specify location as a quoted string.

  • In a routine, you can specify location as label (a line label in the current routine), ^routine (the beginning of a specified external routine), or label^routine (a specified label in a specified external routine). Do not specify a location in a routine that references a procedure or a label within a procedure. This is a invalid location; it results in a runtime error when Caché attempts to execute $ZTRAP.

  • In a procedure, you can specify location as label; a private label within that procedure block. $ZTRAP in a procedure block cannot be used to go to a location that is outside the body of the procedure; $ZTRAP in a procedure block can only reference a location within that procedure block. Therefore, in a procedure you cannot set $ZTRAP to ^routine or label^routine. Attempted to do so results in a <SYNTAX> error.

    In a procedure, you set $ZTRAP to a private label name, but the $ZTRAP value is not the private label name; it is the offset from the procedure label (the top of the procedure) to the line location of the private label. For example, +17^myproc.

Note:

$ZTRAP provides legacy support for label+offset in some contexts (but not in procedures). This optional +offset is an integer specifying the number of lines to offset from label. The label must be in the same routine. The use of +offset is deprecated, and may result in a compilation warning error. InterSystems recommends that you avoid the use of a line offset when specifying location.

You cannot specify an +offset when calling a procedure or a CACHESYS % routine. If you attempt to do so, Caché issues a <NOLINE> error.

The $ZTRAP location must be in the current namespace. $ZTRAP does not support extended routine reference.

If you specify a nonexistent line label, a location that does not exist in the current routine, the following occurs:

  • Displaying $ZTRAP: In a routine, $ZTRAP contains label^routine. For example, DummyLabel^MyRou. In a procedure, $ZTRAP contains the maximum possible offset: +34463^MyProc.

  • Invoking $ZTRAP: Caché issues a <NOLINE> error message.

Each stack level can have its own $ZTRAP value. When you set $ZTRAP, the system saves the value of $ZTRAP for the previous stack level. Caché restores this value when the current stack level ends. To enable error trapping at the current stack level, set $ZTRAP to the error trap handler by specifying its location. For example:

   IF $ZTRAP="" {WRITE !,"$ZTRAP not set" }
   ELSE {WRITE !,"$ZTRAP already set: ",$ZTRAP
         SET oldtrap=$ZTRAP }
   SET $ZTRAP="Etrap1^Handler"
   WRITE !,"$ZTRAP set to: ",$ZTRAP
   //  program code
   SET $ZTRAP=oldtrap
   WRITE !,"$ZTRAP restored to: ",$ZTRAP

When an error occurs, this format unwinds the call stack and transfers control to the specified error trap handler.

In SqlComputeCode, do not set $ZTRAP=$ZTRAP. This can result in significant problems with transactional processing and error reporting.

To disable error trapping, set $ZTRAP to the null string (""). This clears any error trap set at the current DO stack level.

When you set an error handler using $ZTRAP, this handler takes precedence over any existing $ETRAP error handler. Caché implicitly performs a NEW $ETRAP command and sets $ETRAP to the null string ("").

Note:

Use of $ZTRAP from the Terminal prompt is limited to the current line of code. The SET $ZTRAP command and the command generating the error must be in the same line of code. The Terminal restores $ZTRAP to the system default at the beginning of each command line.

*Location

In a routine, you can choose to leave the call stack as it is after the error has occurred. To do so, place an asterisk (*) before location and within the double quotes. This form is not valid for use within procedures; attempted to do so results in a <SYNTAX> error. It can only be used in subroutines that are not procedures, as in this example:

Main
   SET $ZTRAP="*OnError"
   WRITE !,"$ZTRAP set to: ",$ZTRAP
  // program code
OnError
   // Error handling code
   QUIT

This format simply causes a GOTO to the line label specified in $ZTRAP; $STACK and $ESTACK are unchanged. The context frame of the $ZTRAP error handling routine is the same as the context frame where the error occurred. However, Caché resets $ROLES to the value that was in effect for the execution level at which $ZTRAP was set; this prevents the $ZTRAP error handler from using elevated privileges that were granted to the routine after establishing the error handler. Upon completion of the $ZTRAP error handling routine, Caché unwinds the stack to the previous context level. This form of $ZTRAP is especially useful for analyzing unexpected errors.

Note that the asterisk sets a $ZTRAP option; it is not part of the location. For this reason, this asterisk does not display when performing a WRITE or ZZDUMP on $ZTRAP.

^%ETN

In a routine, SET $ZTRAP="^%ETN" establishes the system-supplied error routine %ETN as the current error trap handler. %ETN executes in the context in which the error occurred that invoked it. (%ET is a legacy name for %ETN. Their functionality is identical, though %ETN is slightly more efficient.) The error handlers ^%ETN and ^%ET always behave as if they were preceded by an asterisk (*).

Because $ZTRAP in a procedure block cannot be used to go to a location that is outside the body of the procedure, SET $ZTRAP="^%ETN" cannot be used in a procedure. Attempting to do so results in a <SYNTAX> error.

For more information on %ETN and its entrypoints FORE^%ETN, BACK^%ETN, and LOG^%ETN, see the “Logging Application Errors” section of the “Error Processing” chapter of Using Caché ObjectScript.

TRY / CATCH and $ZTRAP

You cannot set $ZTRAP within a TRY block. Attempting to do so generates a compilation error. You can set $ZTRAP prior to the TRY block, or within the CATCH block.

An error that occurs within a TRY block is handled by the CATCH block, regardless of whether a $ZTRAP has previously been set. An error that occurs within a CATCH block is handled by the current error trap handler.

The first of the following examples shows an error occurring in a TRY block. The second of the following examples shows an exception being thrown in a TRY block. In both cases, the CATCH block, not the $ZTRAP, is taken:

  SET $ZTRAP="Ztrap"
  TRY { WRITE 1/0 }    /* divide-by-zero error */
  CATCH { WRITE "Catch taken" }
  QUIT
Ztrap
  WRITE "$ZTRAP taken"
  SET $ZTRAP=""
  QUIT
  SET $ZTRAP="Ztrap"
  TRY { SET myvar=##class(Sample.MyException).%New("Example Error",999,,errdatazero)
        WRITE !,"Throwing an exception!",!
        THROW myvar
        QUIT  }
  CATCH { WRITE "Catch taken" }
  QUIT
Ztrap
  WRITE "$ZTRAP taken"
  SET $ZTRAP=""
  QUIT

However, a TRY block can call code that sets and uses $ZTRAP. In the following example, the divide-by-zero error is caught by $ZTRAP, rather than the CATCH block:

  TRY { DO Errsub } 
  CATCH { WRITE "Catch taken" }
  QUIT
Errsub
  SET $ZTRAP="Ztrap"
  WRITE 1/0   /* divide-by-zero error */
  QUIT
Ztrap
  WRITE "$ZTRAP taken"
  SET $ZTRAP=""
  QUIT

A THROW command from a CATCH block can also invoke a $ZTRAP error handler.

Examples

The following example sets $ZTRAP to the OnError routine in this program. It then calls SubA in which an error occurs (attempting to divide a number by 0). When the error occurs, Caché calls the OnError routine specified in $ZTRAP. OnError is invoked at the context level at which $ZTRAP was set. Because OnError is at the same context level as Main, execution does not return to Main.

Main
   NEW $ESTACK
   SET $ZTRAP="OnError"
   WRITE !,"$ZTRAP set to: ",$ZTRAP
   WRITE !,"Main $ESTACK= ",$ESTACK   // 0
   WRITE !,"Main $ECODE= ",$ECODE
   DO SubA
   WRITE !,"Returned from SubA"   // not executed
   WRITE !,"MainReturn $ECODE= ",$ECODE
   QUIT
SubA
   WRITE !,"SubA $ESTACK= ",$ESTACK   // 1
   WRITE !,6/0    // Error: division by zero
   WRITE !,"fine with me"
   QUIT
OnError
   WRITE !,"OnError $ESTACK= ",$ESTACK   // 0
   WRITE !,"$ECODE= ",$ECODE
   QUIT

The following example is identical to the previous example, with one exception: The $ZTRAP location is prefaced by an asterisk (*). When the error occurs in SubA, this asterisk causes Caché to call the OnError routine at the context level of SubA (where the error occurred), not at the context level of Main (where $ZTRAP was set). Therefore, when OnError completes, execution returns to Main at the line following the DO command.

Main
   NEW $ESTACK
   SET $ZTRAP="*OnError"
   WRITE !,"$ZTRAP set to: ",$ZTRAP
   WRITE !,"Main $ESTACK= ",$ESTACK   // 0
   WRITE !,"Main $ECODE= ",$ECODE
   DO SubA
   WRITE !,"Returned from SubA"   // executed
   WRITE !,"MainReturn $ECODE= ",$ECODE
   QUIT
SubA
   WRITE !,"SubA $ESTACK= ",$ESTACK   // 1
   WRITE !,6/0    // Error: division by zero
   WRITE !,"fine with me"
   QUIT
OnError
   WRITE !,"OnError $ESTACK= ",$ESTACK   // 1
   WRITE !,"$ECODE= ",$ECODE
   QUIT

See Also

FeedbackOpens in a new tab