BEGIN SEQUENCE

BEGIN SEQUENCE

Define a sequence of statements for a BREAK

Syntax

      BEGIN SEQUENCE
         <statements>...
         [BREAK [<exp>]]
              <statements>...
         [RECOVER [USING <idVar>]]
              <statements>...
      END [SEQUENCE]

Arguments

BREAK <exp> branches execution to the statement immediately following the nearest RECOVER statement if one is specified or the nearest END SEQUENCE statement.

<exp> is the value returned into the <idVar> specified in the USING clause of the RECOVER statement.

RECOVER USING <idVar> defines a recover point in the SEQUENCE construct where control branches after a BREAK statement. If USING <idVar> clause is specified, <idVar> receives the value returned by the BREAK statement. In general, this is an error object.

END defines the end point of the SEQUENCE control structure. If no RECOVER statement is specified, control branches to the first statement following the END statement after a BREAK.

Description

BEGIN SEQUENCE…END is a control structure used for exception and runtime error handling. It delimits a block of statements, including invoked procedures and user-defined functions. When a BREAK is encountered anywhere in a block of statements following the BEGIN SEQUENCE statement up to the corresponding RECOVER statement, control branches to the program statement immediately following the RECOVER statement. If a RECOVER statement is not specified, control branches to the statement following the END statement, terminating the SEQUENCE. If control reaches a RECOVER statement without encountering a BREAK, it branches to the statement following the corresponding END.

The RECOVER statement optionally receives a parameter passed by a BREAK statement that is specified with a return value. This is usually an error object, generated and returned by the current error handling block defined by ERRORBLOCK(). If an error object is returned, it can be sent messages to query information about the error. With this information, a runtime error can be handled within the context of the operation rather than in the current runtime error handler. See the example below.

Within a SEQUENCE construct there are some restrictions on what statements are allowed between the BEGIN SEQUENCE and RECOVER statements. You cannot RETURN, LOOP, or EXIT between a BEGIN SEQUENCE and RECOVER statement. From within the RECOVER statement block, however, you can LOOP, EXIT, BREAK, or RETURN since the SEQUENCE is essentially completed at that point. Using LOOP from within the RECOVER statement block is useful for re-executing the SEQUENCE statement block. See the example below.

SEQUENCE constructs are quite flexible. They can be nested and more than one can be defined in the same procedure or user-defined function. If more than one SEQUENCE construct is specified, each SEQUENCE should delimit one discrete operation.

     For more information on error objects, refer to the Error class.

Examples

       .  This code fragment demonstrates a SEQUENCE construct in which
          the BREAK occurs within the current procedure:
          BEGIN SEQUENCE
             <statements>...
             IF lBreakCond
                BREAK
             ENDIF
          RECOVER
             <recovery statements>...
          END
          <recovery statements>...
       .  This example demonstrates an error handler returning an error
          object to the variable specified in the USING clause of the RECOVER
          statement:
          LOCAL objLocal, bLastHandler
          //
          // Save current and set new error handler
          bLastHandler := ERRORBLOCK({ |objErr| ;
                MyHandler(objErr, .T.) })
          //
          BEGIN SEQUENCE
             .
             . <operation that might fail>
             .
          RECOVER USING objLocal
             //
             // Send messages to objLocal and handle the error
             ? "Error: "
             IF objLocal:genCode != 0
                ?? objLocal:description
             ENDIF
             .
             .
             .
          END
          //
          // Restore previous error handler
          ERRORBLOCK( bLastHandler )
          FUNCTION MyHandler( objError, lLocalHandler )
             //
             // Handle locally returning the error object
             IF lLocalHandler
                BREAK objError
             ENDIF
             .
             . <other statements to handle the error>
             .
             RETURN NIL
       .  This example re-executes a SEQUENCE statement block by LOOPing
          from within the RECOVER statement block:
          DO WHILE .T.
             BEGIN SEQUENCE
                .
                . <operation that may fail>
                .
             RECOVER
                IF PrintRecover()
                   LOOP      // Repeat the SEQUENCE statement block
                ENDIF
             END
             EXIT            // Escape from the operation
          ENDDO

See also:

Error class, ERRORBLOCK(), RETURN

ErrorSys()

ERRORSYS()

Install default error handler

Syntax

      ERRORSYS() --> NIL

Arguments

None.

Returns

ERRORSYS() always return NIL.

Description

ERRORSYS() is called upon startup by Harbour and installs the default error handler. Normally you should not call this function directly, instead use ERRORBLOCK() to install your own error handler.

Compliance

Clipper

Files

Library is rtl

Seealso

ERRORBLOCK(), Error class

C5DG-7 DBFNTX Driver

Clipper 5.x – Drivers Guide

Chapter 7

DBFNTX Driver Installation and Usage

DBFNTX is the default RDD for Clipper. This new database driver replaces the DBFNTX database driver supplied with earlier versions of Clipper and adds a number of new indexing features. With DBFNTX, you can:

. Create conditional indexes by specifying a FOR condition

. Create indexes using a record scope or WHILE condition, allowing you to INDEX based on the order of another index

. Create both ascending and descending order indexes

. Specify an expression that is evaluated periodically during indexing in order to display an index progress indicator

In This Chapter 

This chapter explains how to install DBFNTX and how to use it in your applications. The following major topics are discussed:

. Overview of the DBFNTX RDD

. New Locking Scheme

. Conditional Indexing

. Installing DBFNTX Driver Files

. Linking the DBFNTX Driver

. Using the DBFNTX Driver

. Compatibility with dBASE III

Overview of the DBFNTX RDD

As an update of the default database driver, DBFNTX is linked into and used automatically by your application unless you compile using the /R option.

New Features

The replaceable driver lets you create and maintain (.ntx) files using features above and beyond those supplied with the previous DBFNTX driver. The new indexing features are supplied in the form of several syntactical additions to the INDEX and REINDEX commands. Specifically you can:

. Specify full record scoping and conditional filtering using the standard ALL, FOR, WHILE, NEXT, REST, and RECORD clauses

. Create an index while another controlling index is still active

. Monitor indexing as each record (or a specified record number interval) is processed using the EVAL and EVERY clauses

. Eliminate separate coding for descending order keys using the DESCENDING clause

Compatibility

Index files (.ntx) created with the original DBFNTX driver are compatible with DBFNTX and can be used in new applications without reindexing. Index files (.ntx) created with this version of DBFNTX will also work with previous Clipper applications provided that you use no FOR, WHILE, <scope>, or DESCENDING clauses.

Important! Indexes produced with DBFNTX using FOR or DESCENDING are incompatible with earlier version (.ntx) files. If you attempt to access them with the original DBFNTX database driver or programs compiled with versions earlier than Clipper 5.2, you will get an unrecoverable runtime error. In Clipper, this generates an “index corrupted” error message, causing the application to terminate.

New Locking Scheme

The DBFNTX database driver implements a new locking scheme to resolve several problems identified in previous versions of Clipper and to prevent potential problems that might arise when running Clipper applications in a network environment. This section discusses these changes and their implications, including compatibility issues.

Lock Time-outs

Problem: Index locking in previous versions of Clipper was handled automatically by the database driver, and had no time-out provision. This created the potential for problems in network environments if a workstation died while holding a lock. If this situation occurred all other workstations waiting for an index lock would appear to freeze while waiting to obtain their lock. This could also happen if a user placed a Clipper application in the background on a multitasking system without sufficient processing time allocated to it. Eventually, most network operation systems would clear a connection that had no activity for a specified period of time. This would free the lock and everything would resume as normal, but frustrated users may have rebooted their machines possibly causing file corruption.

Solution: In Clipper 5.2 the NTX driver will generate a recoverable runtime error if it fails to lock the index after a predetermined number of retries. The default error handler for this system simply returns (.T.) to retry the operation. This emulates the behavior of previous Clipper versions.

Error Handling

Time out handling: The handling of this error is problematic because the lock is issued from various internal index routines. Therefore the only safe recoveries are to retry or quit. Choosing to default from the error or issuing a break will more than likely leave the index in a corrupted state. If either of the options is employed, the application should immediately recreate the index. The preferred way to handle a time out such as this is to alert the user of the situation so they don’t think their machine has hung, and then have the network administrator determine what workstation is causing the problem. When the problem workstation is cleared, the users that have timed out can select retry and continue processing.

NTXERR.PRG: The file NTXERR.PRG contains the source code for the default error handler INIT procedure. This error handler can be modified to allow user-defined error handling for index lock time-outs. Care should be exercised when modifying the error handler as detailed above.

Compatibility: The lock time-out capability when used in conjunction with the default error handler is totally compatibility with previous versions of Clipper. No changes are made to the NTX file structure and no action is required by the developer to activate the time-out functionality.

New Lock Offset

Problem: Index locking, which is transparent to the developer, uses a single-byte semaphore locking system. This semaphore was placed at a virtual offset (beyond the physical end of file) in the index file. In previous versions of Clipper, this offset was located at one billion (1,000,000,000) which was adequate at the time. But many systems today are capable of producing indexes that are large enough to cause the actual data present at the lock offset to become physically locked. This leads to problems when trying to read or write to the data at that offset.

Solution: The solution is to move the offset where locking occurs to a location at a greater offset. We have chosen FFFFFFFF hex, which is the largest offset possible under the DOS operating system. The problem with this solution is that new applications using the index will be locking this new byte while old applications using the same index will lock the old position. Clearly this would cause both applications to fail because each could have a lock on the file at the same time.

To avoid this, the signature of the index (in the index header) is modified to prevent pre-Clipper 5.2 applications from being able to open the index. Clipper 5.2 applications can detect the correct offset to use by the flag in the header and will automatically use the correct one. In Figure 7-1 below, each bit represents a flag:

BIT  7 6 5 4 3 2 1 0
FLAG R R R O P I I C
R Reserved
I Index type - both bits set (NTX)
C Index created with a Condition, condition in header
T Created as a Temporary index
O New Offset for exclusive (semaphore) lock
Figure 7-1: Bit Field for the Signature Byte of a -Clipper 5.2 NTX File

Activation

If Clipper 5.2 automatically modified the signature in the header when it created indexes, programs with automatic reindexing routines would be creating indexes that appeared corrupt to pre-Clipper 5.2 applications. This has an obvious problem with backward compatibility. Therefore, in order to create indexes with the new signature, the developer must link in the module NTXLOCK2.OBJ with the full knowledge that this will create indexes that older applications will not be able to access.

Header Changes

The signature byte of a .NTX file is 6 for an unenhanced NTX index. The inclusion of the NTXLOCK2.OBJ will cause the signature to become 26 hex. (6 hex ORed with 20 hex). See Figure 7-1 for an illustration of all the possible values for the signature byte.

Error Handling

Clipper 5.2 applications will automatically recognize the signature byte of the header, and depending on the signature value, will use the correct index lock location. Applications built with previous versions of Clipper, however, do not have the capability to detect the optional new information in the signature byte. Therefore, when an order application tries to open a file that has been created with the NTXLOCK2.OBJ linked in it will produce a Corruption Detected error.

Compatibility

The new locking location, if used, is not backward compatible with applications compiled with previous versions of Clipper.

Indexes created by applications built with a previous version of Clipper can be used by Clipper 5.2 using the new location and will not be modified unless the index is recreated in application.

Since older applications have no knowledge of the new index locking scheme nor of the significance of the header signature, these applications will assume the index is corrupt and will produce an Index Corrupted error.

Conditional Indexing

Conditional indexes are a feature of the DBFNTX driver. This section discusses this feature of the DBFNTX driver in some detail, giving you specific information about the implementation of conditional indexes. Compatibility issues are also discussed.

Conditional Indexes

Conditional indexes are produced by using a FOR condition in the index creation process. These indexes are made fully maintainable by storing the FOR condition in the index header. This condition is subsequently retrieved and compiled each time the index in opened. During updates, items are added to the index only if they meet the criteria of the condition.

Since older applications do not have the ability to recognize and use the condition stored in the header, they must be prevented from opening the index since they corrupt the index. This is accomplished by modifying the signature of the index (in the index header) preventing pre-Clipper 5.2 applications from being able to open the index. Clipper 5.2 applications can detect the flag in the header and will automatically use the stored FOR condition correctly.

Temporary Indexes

Temporary indexes are produced by using any scoping clause other than the FOR condition in the index creation process. These indexes are not automatically maintainable because the condition is not stored for later use. These indexes can be made maintainable if the condition can be expressed as a FOR condition and is added using the FOR clause. But the main use of temporary indexes is for fast creation of indexes for read- only browses or reports that operate on a subset of the database.

Since older applications would not operate properly with indexes that do not contain all the keys in a given database, they must be prevented from using them. This is accomplished by modifying the index signature to prevent pre-Clipper 5.2 applications from being able to open the index.

Activation

Conditional Indexes

The developer need only specify the FOR condition when creating the index. In doing so he must be fully aware the index will no longer be accessible to pre–Clipper 5.2 applications.

Temporary Indexes

The developer need only specify a scope other than FOR when creating the index. In doing so he must be fully aware the index will no longer be accessible to pre-Clipper 5.2 applications and that the index created is not maintainable.

Header Changes

The signature byte of a .NTX file is 6 for a unenhanced NTX index. If the index is created as a conditional index it will have a signature of 7 hex (6 hex ORed with 1 hex). If the index is created as a temporary index it will have a signature of E hex. (6 hex ORed with 8 hex). See Figure 7-1 for an illustration of all the possible values for the signature byte.

Error Handling

Corruption Detected

Since older applications have no knowledge of the new index features nor how to interpret the additional flags in the header signature, these applications will assume the index is corrupt and will produce an Index Corrupted error.

EOF()

If an index is created with a FOR condition and an attempt is made to update the index with a key that does not match the condition, the update is suppressed and the index is placed at EOF(). This is consistent with the current behavior for indexes created with the unique flag when an update is attempted with a non-unique key.

Also if a navigational action is attempted (SKIP) and the current record is not found in the index, the index will place the record pointer at EOF(). This is true for both conditional and temporary indexes.

Compatibility

Backward Compatibility

If the conditional or temporary indexing features are used the index produced will not be backward compatible with applications compiled with previous versions of Clipper. Indexes that do not use the features, however, will be 100% compatible.

Forward Compatibility

Indexes created by applications built with a previous version of Clipper can be used by Clipper 5.2 and will not be modified unless the index is recreated using either the conditional or temporary index features.

Error Message Produced by Old Applications

Since older applications have no knowledge of the new index locking scheme nor of the significance of the header signature, these applications will assume the index is corrupt and will produce an Index Corrupted error.

Installing DBFNTX Driver Files

DBFNTX is supplied as the file DBFNTX.LIB.

The Clipper installation program installs this driver as the default in the \CLIPPER5\LIB subdirectory on the drive that you specify, so you need not install the driver manually.

Important! Before installing Clipper, you may want to rename the DBFNTX.LIB that currently resides in your \CLIPPER5\LIB directory to DBFNTX.001. The new version, when installed, will overwrite DBFNTX.LIB. If you do not rename or otherwise protect the old version of DBFNTX.LIB, you will lose it.

Linking the DBFNTX Database Driver

Since DBFNTX is the default database driver for Clipper, there are no special instructions for linking. Unless you specify the /R option when you compile, the new driver will be linked into each program automatically if you specify a USE command or DBUSEAREA() function without an explicit request for another database driver. The driver is also linked if you specify an INDEX or REINDEX command with any of the new features.

Using the DBFNTX Database Driver

In applications written for the new DBFNTX driver, you can use the INDEX and REINDEX commands exactly as you have used them in the past. The index files (.ntx) you create and maintain in this way are completely compatible with those created using previous versions of the driver.

Changes to existing code are necessary only if you use the new indexing features. The (.ntx) files you create using the new features will have a slightly different header file and cannot be used by programs linked with a previous version of the driver.

Using (.ntx) and (.ndx) Files Concurrently

You can use (.ntx) and (.ndx) files concurrently in a Clipper program like this:

// (.ntx) file using default DBFNTX driver

USE File1 INDEX File1 NEW

// (.ndx) files using DBFNDX driver

USE File2 VIA "DBFNDX" INDEX File2 NEW

Note, however, that you cannot use (.ntx) and (.ndx) files in the same work area. For example, the following does not work:

USE File1 VIA "DBFNDX" INDEX File1.ntx, File2.ndx

Compatibility with dBASE III PLUS

The default DBFNTX driver makes Clipper programs behave differently than traditional dBASE programs. Some of these differences are discussed below.

Supported Data Types

The DBFNTX database driver supports the following dBASE III PLUS- compatible data types for key expressions:

. Character

. Numeric

. Date

. Logical

Supported Key Expressions

When you create (.ntx) files using the DBFNTX driver, you can use all Clipper or user-defined functions compatible with dBASE III PLUS as well as other functions accepted by the extended Clipper functionality.

Error Handling

The indexing behavior of DBFNTX and DBFNDX in a Clipper application is identical unless otherwise noted. With the default DBFNTX driver, you can handle most errors using BEGIN SEQUENCE…END SEQUENCE as illustrated in the next section.

FIND vs SEEK

In Clipper, you can use the FIND command only to locate keys in indexes where the index key expression is character data type. This differs from dBASE III PLUS where FIND supports character and numeric key values.

Note: In Clipper programs, always use the SEEK command or the DBSEEK() function to search an index for a key value.

The DBFNTX driver lets you recover from data type errors raised during a FIND or SEEK. However, since Error:canDefault, Error:canRetry or Error:canSubstitute are set to false (.F.), you should use BEGIN SEQUENCE…END to handle such SEEK or FIND data type errors. Within the error block for the current operation, issue a BREAK() using the error object that the DBFNTX database driver generates, like this:

bOld := ERRORBLOCK({|oError| BREAK(oError)})
 .
 .
 .
 BEGIN SEQUENCE
     SEEK xVar
 RECOVER USING oError
     // Recovery code END
 .
 .
 .
 ERRORBLOCK(bOld)

There is an extensive discussion of the effective use of the Clipper error system in the Error Handling Strategies chapter of the Programming and Utilities guide.

Sharing Data on a Network

The DBFNTX driver provides file and record locking schemes that are different from dBASE III PLUS schemes. This means that if the same database and index files are open in Clipper and in dBASE III PLUS, Clipper program locks are not visible to dBASE III PLUS and vice versa.

Warning! Database integrity is not guaranteed and index corruption will occur if Clipper and dBASE III PLUS programs attempt to write to a database or index file at the same time. Therefore, concurrent use of the same database (.dbf) and index (.ndx) files by dBASE III PLUS and Clipper programs is strongly discouraged and not supported by Computer Associates.

Summary

In this chapter, you were given an overview of the new features of the default DBFNTX RDD. You learned how to this driver is automatically linked and how to use it in your applications, and were given an overview of the compatiblity issues.

C5DG-6 DBFNDX Driver

Clipper 5.x – Drivers Guide

Chapter 6

DBFNDX Driver Installation and Usage

DBFNDX is the dBASE III PLUS compatible RDD for Clipper. The DBFNDX driver uses the Clipper driver architecture to access dBASE III PLUS compatible index files within a Clipper program.

In This Chapter

This chapter explains how to install DBFNDX and how to use it in your applications. The following major topics are discussed:

. Overview of the DBFNDX RDD

. Installing DBFNDX Driver Files

. Linking the DBFNDX Driver

. Using the DBFNDX Driver

. Compatibility with dBASE III PLUS

Overview of the DBFNDX RDD

The DBFNDX database driver allows creation, access, and updating of dBASE III and dBASE III PLUS compatible index (.ndx) files. Index files (.ndx) created with Clipper are exactly the same as those created by dBASE III PLUS. All operations that can be performed on standard Clipper index (.ntx) files can be performed on (.ndx) files using the DBFNDX database driver.

In a network environment, the DBFNDX driver supports the Clipper file and record locking scheme. The multiuser behavior is the same as the default DBFNTX driver. This means that the DBFNDX database driver supports concurrent access to (.ndx) files between Clipper applications only. Concurrent access to (.ndx) files between dBASE III PLUS and Clipper programs is not supported.

Important! Updating database (.dbf) and index (.ndx) files shared between dBASE III PLUS and Clipper programs may corrupt the (.dbf) and any of its associated (.ndx) files.

Installing DBFNDX Driver Files

The DBFNDX database driver is supplied as the file, DBFNDX.LIB.

The Clipper installation program installs this driver in the \CLIPPER5\LIB subdirectory on the drive that you specify, so you need not install the driver manually.

Linking the DBFNDX Database Driver

To link the DBFNDX database driver into an application program, you must specify DBFNDX.LIB to the linker in addition to your application object files (.OBJ).

1. To link with .RTLink using positional syntax:

C>RTLINK <appObjectList> ,,, DBFNDX

2. To link with .RTLink using freeformat syntax:

C>RTLINK FI <appObjectList> LIB DBFNDX

Note: These link commands all assume the LIB, OBJ, and PLL environment variables are set to the standard locations. They also assume that the Clipper programs were compiled without the /R option.

Using the DBFNDX Database Driver

To use (.ndx) files in a Clipper program:

1. Place a REQUEST DBFNDX at the beginning of your application or at the top of the first program file (.prg) that opens a database file using the DBFNDX driver.

2. Specify the VIA “DBFNDX” clause if you open the database file with the USE command.

-OR-

3. Specify “DBFNDX” for the <cDriver> argument if you open the database file with the DBUSEAREA() function.

-OR-

4. Use RDDSETDEFAULT(“DBFNDX”) to set the default driver to DBFNDX.

Except in the case of REQUEST, the RDD name must be a literal character string or a variable. In all cases it is important that the driver name be spelled correctly.

The following program fragments illustrate:

REQUEST DBFNDX 
. 
. 
. 
USE Customers INDEX Name, Address NEW VIA "DBFNDX"

-OR-

REQUEST DBFNDX RDDSETDEFAULT( "DBFNDX" ) 
.
.
. 
USE Customers INDEX Name, Address NEW

Using (.ntx) and (.ndx) Files Concurrently

You can use (.ndx) and (.ntx) files concurrently in a Clipper program like this:

REQUEST DBFNDX

// (.ntx) file using default DBFNTX driver USE File1 INDEX File1 NEW

// (.ndx) files using DBFNDX driver USE File2 VIA “DBFNDX” INDEX File2 NEW

Note, however, that you cannot use (.ndx) and (.ntx) files in the same work area. For example, the following does not work:

USE File1 VIA "DBFNDX" INDEX File1.ntx, File2.ndx

Compatibility with dBASE III PLUS

When accessing dBASE III PLUS (.ndx) files, there are several compatibility issues of which you must be aware. These issues are discussed below.

Supported Data Types

The DBFNDX database driver supports the following data types for key expressions:

. Character

. Numeric

. Date

This is consistent with dBASE III PLUS.

The DBFNDX database driver does not support indexing with logical key expressions as does the default DBFNTX database driver. This is actually a dBASE III PLUS limitation and is not supported by the DBFNDX driver in order to enforce compatibility with dBASE III PLUS.

To work around this limitation, index logical values by converting them to character values like this:

INDEX ON IIF(<lExp>, "T", "F") TO <logicalIndex>

Supported Key Expressions

When you create (.ndx) files using the DBFNDX driver, you must use only Clipper or user-defined functions compatible with dBASE III PLUS. Use of the other functions will render the (.ndx) file unreadable in dBASE III PLUS.

FIND vs SEEK

In Clipper, you can use the FIND command only to locate keys in indexes where the index key expression is character type. This differs from dBASE III PLUS where FIND supports character and numeric key values.

Note: In Clipper programs, always use the SEEK command or the DBSEEK() function to search an index for a key value.

The DBFNDX driver lets you recover from a data type error raised during a FIND or SEEK. However, since Error:canDefault, Error:canRetry, or Error:canSubstitute are set to false (.F.), you should use BEGIN SEQUENCE…END to handle a SEEK or FIND data type error. Within the error block for the current operation, issue a BREAK() using the error object the DBFNDX database driver generates, like this:

bOld := ERRORBLOCK({|oError| BREAK(oError)})
.
.
 .
BEGIN SEQUENCE
SEEK xVar
RECOVER USING oError
// Recovery code
END
.
.
 .
ERRORBLOCK(bOld)

There is an extensive discussion of the effective use of the Clipper error system in the Error Handling Strategies chapter of the Programming and Utilities guide.

Sharing Data on a Network

As mentioned above, the DBFNDX driver does not support dBASE III PLUS file and record locking schemes. Instead, the DBFNDX driver supports the DBFNTX file and record locking scheme. This means that if the same database and index files are open in Clipper and dBASE III PLUS, Clipper program locks are not visible to dBASE III PLUS and vice versa.

Warning! Database integrity is not guaranteed and index corruption will occur if Clipper and dBASE III PLUS programs attempt to write to a database or index file at the same time. For this reason, concurrent use of the same database (.dbf) and index (.ndx) files by dBASE III PLUS and Clipper programs is strongly discouraged and not supported.

Compatibility with dBASE IV

Specific compatibility with dBASE IV is provided through the DBFMDX driver. It includes (.dbf), (.mdx), and (.dbt) file format compatibility and is described in detail in the previous chapter.

Summary

In this chapter, you were given an overview of the features and benefits of the DBFNDX RDD. You learned how to link this driver and how to use it in your applications, and were given an overview of the compatibility issues.

C5_ERRORBLOCK

 ERRORBLOCK()
 Post a code block to execute when a runtime error occurs
------------------------------------------------------------------------------
 Syntax

     ERRORBLOCK([<bErrorHandler>]) --> bCurrentErrorHandler

 Arguments

     <bErrorHandler> is the code block to execute whenever a runtime
     error occurs.  When evaluated, the <bErrorHandler> is passed an error
     object as an argument by the system.

 Returns

     ERRORBLOCK() returns the current error handling code block.  If no error
     handling block has been posted since the program was invoked,
     ERRORBLOCK() returns the default error handling block.

 Description

     ERRORBLOCK() is an error function that defines an error handler to
     execute whenever a runtime error occurs.  Specify the error handler as a
     code block with the following form,

     { |<oError>| <expression list>,... }

     where <oError> is an error object containing information about the
     error.  Within the code block, messages can be sent to the error object
     to obtain information about the error.  Returning true (.T.) from the
     error handling block retries the failed operation and false (.F.)
     resumes processing.

     The error handling code block can be specified either as a list of
     expressions or as a call to a user-defined function.  A call to a user-
     defined function is more useful since you can use Clipper control
     statements instead of expressions.  This is particularly the case if
     there is a BEGIN SEQUENCE pending and you want to BREAK to the nearest
     RECOVER statement.

     As this implies, error handling blocks can be used in combination with
     BEGIN SEQUENCE...END control structures.  Within an error handling
     block, you handle device, low-level, and common errors that have a
     general recovery mechanism.  If the operation needs specific error
     handling, define a BEGIN SEQUENCE then BREAK to the RECOVER statement,
     returning the error object for local processing.  See the example below.

     If no <bErrorHandler> has been specified using ERRORBLOCK() and a
     runtime error occurs, the default error handling block is evaluated.
     This error handler displays a descriptive message to the screen, sets
     the ERRORLEVEL() to 1, then QUITs the program.

     Since ERRORBLOCK() returns the current error handling block, it is
     possible to specify an error handling block for an operation saving the
     current error handling block, then restore it after the operation has
     completed.  Also, error handlers specified as code blocks, can be passed
     to procedures and user-defined functions, and RETURNed as values.

     For more information on the structure and operations of error objects,
     refer to the Error class entry in this chapter and the "Error Handling
     Strategies" chapter in the Programming and Utilities Guide.

 Examples

     .  This code fragment posts, and then calls an error handling
        block when there is an error within a BEGIN SEQUENCE construct:

        LOCAL bErrorHandler, bLastHandler, objErr
        bErrorHandler := { |oError| ;
              MyErrorHandler(oError) }
        //
        // Save current handler
        bLastHandler := ERRORBLOCK(bErrorHandler)
        //
        BEGIN SEQUENCE
           .
           . <operation statements>
           .
        // Receive error object from BREAK
        RECOVER USING oErrorInfo
           .
           . <recovery statements>
           .
        END
        ERRORBLOCK(bLastHandler)      // Restore handler
        RETURN

        FUNCTION MyErrorHandler( oError )
           //
           BREAK oError      // Return error object to RECOVER
           RETURN NIL

 Files   Library is CLIPPER.LIB.

See Also: BEGIN SEQUENCE



RTE (Runtime error)

What is a RTE (Runtime error) ?

There are four ways that a Clipper program can terminate fatally. Each of these types of terminations represent different causes for the termination and need to be considered separately.

Runtime recoverable errors :

Runtime recoverable errors are expected to happen. These errors generally occur either because of mistakes in your code (e.g. type mismatch, divide by zero) or because of some condition of the environment (e.g. out of file handles, file sharing violations, memory low). These errors can be trapped in the error system and therefore do not necessarily terminate the application.

If the default error system is being used in the application then runtime errors are reported in the following format:

Error | Warning <subSystem>/<subCode> <message text>
              <filename> | <operation>

Overview on error recovery :

Error recovery failure

Clipper’s error system depends on communication taking place between the error handler and the subsystem that generates the error. The error handler communicates with the subsystem by returning a value indicating what the subsystem should attempt to do to recover from the error. The legal values that can be returned are determined by the values contained in the error object passed to the error handler for Error:canRetry, Error:canDefault, and Error:canSubstitute. If the error handler returns an invalid value to the subsystem (or returns to the subsystem at all when these values are all false), then an error recovery failure is reported and the application is terminated.

This exit condition always has the same format:

Error recovery failure, <operation> (<line number>)

User abort :

The user can abort your application by pressing Alt-C or Ctrl-Break at anytime during the execution of your application unless you have specifically disabled this feature. You can disable it with SETCANCEL (.F.) or SET(_SET_CANCEL, .F.).

This exit condition always has the same format:

Cancelled at: <operation> (<line number>)

Missing error handler :

If code is executed before any ERRORBLOCK() can be installed, an unrecoverable error will be generated that indicates that no error handler is present. This usually occurs if there is code in ErrorSys() before the ERRORBLOCK() function is called. All code should be moved after this line if possible.

No ERRORBLOCK() for error at: <operation>
    (<line number>)

Runtime recoverable error categories :

This section is a summary of runtime recoverable error messages that are possible when executing a Clipper application using the supplied subsystems. The messages are divided into categories according to subsystem. Each category is described below, followed by a listing of all messages in each category.

BASE Errors :

BASE error messages indicate errors generated by the Base system.

The general format of a BASE error message is as follows:

Error | Warning BASE/xxxx <message text> <filename> |
     <operation>
TERM Errors :

TERM error messages indicate errors generated by the Terminal subsystem. The general format of a TERM error message is as follows:

Error | Warning TERM/xxxx <message text> <filename> |
     <operation>
DBFNTX Errors :

DBFNTX error messages indicate that an error occurred during a database or index operation utilizing the DBFNTX database driver. The general format of a DBFNTX error message is as follows:

Error | Warning DBFNTX/xxxx <message text>
 <filename> | <operation>
DBFNDX Errors :

DBFNDX error messages indicate that an error occurred during a database or index operation utilizing the DBFNDX database driver. The general format of a DBFNDX error message is as follows:

Error | Warning DBFNDX/xxxx <message text>
      <filename> | <operation>
DBCMD Errors :

DBCMD error messages occur in the database command set and are unrelated to a particular driver. They occur as a result of command usage rather than from a failure of the driver itself.

Error | Warning DBCMD/xxxx <message text>
       <filename> | <operation>

Runtime unrecoverable errors :

Unrecoverable errors are runtime errors that for some reason cannot make use of the error system. Like runtime errors, it is normal for these errors to occur. This is usually because the system is unable to execute the error block. Almost all of these errors are therefore related to the environment (e.g. out of memory, errors reading code to execute from disk) and can be fixed by making a change to the environment.

Unrecoverable errors always have the same format:

<operation> (<line number>) Unrecoverable error xxxx:
     <message text>

C5 Error Handling

C5 Error Handling Commands, Statements and Funtions

Statement :

BEGIN SEQUENCE :

Define a sequence of statements for a BREAK

BEGIN SEQUENCE
    <statements>...
    [BREAK [<exp>]]
    <statements>...
    [RECOVER [USING <idVar>]]
    <statements>...
END [SEQUENCE]

Functions :

ALTD() :

Invoke the Clipper Debugger

ALTD( [ <nAction> ] ) --> NIL

BREAK() :

Branch out of a BEGIN SEQUENCE…END construct

BREAK( <exp> ) --> NIL

DOSERROR() :

Return the DOS error number

DOSERROR( [ <nNewOsCode> ] ) --> nOsCode

ERRORBLOCK() :

Post a code block to execute when a runtime error occurs

ERRORBLOCK( [ <bErrorHandler> ] ) --> bCurrentErrorHandler

ERRORLEVEL() :

Set the Clipper return code

ERRORLEVEL( [ <nNewReturnCode> ] ) --> nCurrentReturnCode

NETERR() :

Determine if a network command has failed

NETERR( [ <lNewError> ] ) --> lError

OUTERR() :

Write a list of values to the standard error device

OUTERR( <exp list> ) --> NIL

PROCLINE() :

Return the source line number of the current or previous activation

PROCLINE( [ <nActivation> ] ) --> nSourceLine

PROCNAME() :

Return the name of the current or previous procedure or user-defined function

PROCNAME( [ <nActivation> ] ) --> cProcedureName

Error Class :

Provides objects containing information about runtime errors.

Description :

An Error object is a simple object that contains information pertaining to a runtime error. Error objects have no methods, only exported instance variables. When a runtime error occurs, CA-Clipper creates a new Error object and passes it as an argument to the error handler block specified with the ERRORBLOCK() function. Within the error handler, the Error object can then be queried to determine the nature of the error condition.

Error objects can also be returned to the RECOVER statement of a BEGIN SEQUENCE construct with a BREAK statement. Here, the error object can be queried for local error handling. For more detailed information and examples refer to the Error Handling Strategies chapter in the Programming and Utilities guide.

Class Function :

ErrorNew() :

Returns a new Error object.

ErrorNew() --> objError

Exported Instance Variables :

args (Assignable) :

An array of function or operator arguments.

Contains an array of the arguments supplied to an operator or function when an argument error occurs. For other types of errors, Error:args contains a NIL value.

canDefault (Assignable) :

Indicates whether or not default recovery is available.

Contains a logical value indicating whether the subsystem can perform default error recovery for the error condition. A value of true (.T.) indicates that default recovery is available. Availability of default handling and the actual default recovery strategy depends on the subsystem and the error condition. The minimum action is simply to ignore the error condition.

Default recovery is requested by returning false (.F.) from the error block invoked to handle the error. Note that Error:canDefault is never true (.T.) if Error:canSubstitute is true (.T.).

canRetry (Assignable) :

Indicates whether or not a retry is possible after an error.

Contains a logical value indicating whether the subsystem can retry the operation that caused the error condition. A value of true (.T.) indicates that a retry is possible. Retry may or may not be available, depending on the subsystem and the error condition.

Retry is requested by returning true (.T.) from the error block invoked to handle the error. Note that Error:canRetry never contains true (.T.) if Error:canSubstitute contains true (.T.).

canSubstitute (Assignable) :

Indicates if a new result can be substituted after an error

Contains a logical value indicating whether a new result can be substituted for the operation that produced the error condition. Argument errors and certain other simple errors allow the error handler to substitute a new result value for the failed operation. A value of true (.T.) means that substitution is possible.

The substitution is performed by returning the new result value from the code block invoked to handle the error. Note that Error:canSubstitute is never true (.T.) if either Error:canDefault or Error:canRetry is true (.T.).

cargo (Assignable) :

User-definable variable.

Contains a value of any data type unused by the Error system. It is provided as a user-definable slot, allowing arbitrary information to be attached to an Error object and retrieved later.

description (Assignable) :

Character description of the error condition.

Contains a character string that describes the error condition. A zero-length string indicates that the subsystem does not provide a printable description for the error. If Error:genCode is not zero, a printable description is always available.

filename (Assignable) :

Name of the file associated with the error

Contains a character value representing the name originally used to open the file associated with the error condition. A zero-length string indicates either that the error condition is not associated with a particular file or that the subsystem does not retain filename information.

genCode (Assignable) :

Error code number.

Contains an integer numeric value representing a CA-Clipper generic error code. Generic error codes allow default handling of similar errors from different subsystems. A value of zero indicates that the error condition is specific to the subsystem and does not correspond to any of the generic error codes. The header file, Error.ch, provides a set of manifest constants for generic error codes.

operation (Assignable) :

Character description of the failed operation.

Contains a character string that describes the operation being attempted when the error occurred. For operators and functions, Error:operation contains the name of the operator or function. For undefined variables or functions, it contains the name of the variable or function. A zero-length string indicates that the subsystem does not provide a printable description of the operation.

osCode (Assignable) :

Operating system error code number

Contains an integer numeric value representing the operating system error code associated with the error condition. A value of zero indicates that the error condition was not caused by an error from the operating system. When Error:osCode is set to a value other than zero DOSERROR() is updated with the same value.

Error:osCode properly reflects the DOS extended error code for file errors. This allows proper distinction between errors which result from sharing violations (e.g., opening EXCLUSIVE when another process has already opened the file) and access violations (e.g., opening read/write when the file is marked read-only).

For a list of DOS error codes please look at here 

severity (Assignable) :

Indicates error severity

Contains a numeric value indicating the severity of the error condition. Four standard values are defined in Error.ch:

Error:severity Values
------------------------------------------------------------
Error.ch        Meaning
------------------------------------------------------------
ES_WHOCARES     The condition does not represent a failure;
                the error is informational.
ES_WARNING      The condition does not prevent further
                operations, but may result in a more serious 
                error later. 
ES_ERROR        The condition prevents further operations without 
                corrective action of some kind. 
ES_CATASTROPHIC The condition requires immediate termination 
                of the application.
------------------------------------------------------------

Note that the Clipper runtime support code only generates errors with severities of ES_WARNING or ES_ERROR

subCode (Assignable) :

Subsystem-specific error code number.

Contains an integer numeric value representing a subsystem-specific error code. A value of zero indicates that the subsystem does not assign any particular number to the error condition.

subSystem (Assignable) :

Character description of the subsystem generating the error.

Contains a character string representing the name of the subsystem generating the error. For errors with basic CA-Clipper operators and functions, the subsystem name “BASE” is given. For errors generated by a database driver, Error:subSystem contains the name of the database driver

tries (Assignable) :

Number of times the failed operation has been attempted.

Contains an integer numeric value representing the number of times the failed operation has been attempted. When Error:canRetry is true (.T.), Error:tries can be used to limit the number of retry attempts. A value of zero indicates that the subsystem does not track the number of times the operation has been tried.

Examples :

. This example demonstrates how a file open operation might be handled in an error handler replicating the default CA-Clipper behavior. When, for example, an attempt to open a database file with a USE command fails, control returns to the statement following the offending command:

#include "Error.ch"
#command RETRY => RETURN (.T.) // Retry operation
#command RESUME => RETURN (.F.) // Default recovery
//
FUNCTION MyError( objError )
   //
   // Handle file open error
   IF objError:genCode == EG_OPEN .AND.;
      objError:canDefault .AND.;
      NETERR()
   //
      RESUME
   ENDIF
  .
  . <other error statements>
  .
RETURN NIL

. This example retries an operation within an error handler a specified number of times:

 #include "Error.ch"
 #command RETRY => RETURN (.T.) // Retry operation
 #command RESUME => RETURN (.F.) // Default recovery
 //
FUNCTION MyError( objError )

 // Handle printer not ready error
 IF objError:genCode == EG_PRINT .AND.;
    objError:canRetry .AND.;
    objError:tries < 25

    RETRY
 ENDIF
 .
 . <other error statements>
 .
 RETURN NIL

. This code fragment returns an error object from an error handler to the RECOVER statement for further processing:

LOCAL objLocal, bLastHandler
// Save current and set new error handler
bLastHandler := ERRORBLOCK({ |objErr| ;
MyHandler(objErr, .T.)})
BEGIN SEQUENCE
   .
   . <operation that might fail>
   .
   RECOVER USING objLocal
   .
   . <send messages to objLocal and handle the error>
   .
END
// Restore previous error handler
ERRORBLOCK( bLastHandler )
FUNCTION MyHandler( objError, lLocalHandler )

    // Handle locally returning the error object
    IF lLocalHandler
       BREAK objError
    ENDIF
    .
    . <other statements to handle the error>
    .
RETURN NIL

Files: Header file is Error.ch, default error handler is in Errorsys.prg.