Icon Exception Handling and Errors

One of the first items to address in any application, and especially a database application, is how to anticipate and gracefully handle exceptions. This is true as well with ElevateDB.

ElevateDB Exception Types
ElevateDB uses the EEDBError object as its exception object for all errors. This object descends from the EDatabaseError exception object defined in the common DB unit, which itself descends from the common Exception object. This hierarchy is important since it allows you to isolate the type of error that is occurring according to the type of exception object that has been raised, as you will see below when we demonstrate some exception handling.

Information ElevateDB also raises certain component-level exceptions as an EDatabaseError to maintain consistency with the way the common DB unit and TDataSet component behaves. These mainly pertain to design-time property modifications, but a few can be raised at runtime also.

The EEDBError object contains several important properties that can be accessed to discover specific information on the nature of the exception. The ErrorCode property is always populated with a value which indicates the error code for the current exception. Other properties may or may not be populated according to the error code being raised, and a list of all of the error codes raised by the ElevateDB engine along with this information can be found in Appendix A - Error Codes and Messages.

Exception Handling
The most basic form of exception handling is to use the try..except block (Delphi and Lazarus) or try..catch (C++) to locally trap for specific error conditions. The error code that is returned when an open fails due to an exclusive lock problem is 300, which is defined as EDB_ERROR_LOCK in the edberror unit. The following example shows how to trap for such an exception on open and display an appropriate error message to the user:

{
      {
      MyEDBTable->DatabaseName="Tutorial";
      MyEDBTable->TableName="customer";
      MyEDBTable->Exclusive=true;
      MyEDBTable->ReadOnly=False;
      try
         {
         MyEDBTable->Open();
         }
      catch(const Exception &E)
         {
         if (dynamic_cast<EDatabaseError*>(E) &
             dynamic_cast<EEDBError*>(E))
            {
            if (dynamic_cast<EEDBError&>(*E)->ErrorCode==
                EDB_ERROR_LOCK)
               {   
               ShowMessage("Cannot open table "+TableName+
                    ", another user has the table open already");
               }
            else
               {
               ShowMessage("Unknown or unexpected "+
                    "database engine error # +IntToStr(
                    dynamic_cast<EEDBError&>(*E)->ErrorCode));
               }
            }
         else
            {
            ShowMessage("Unknown or unexpected "+
                    "error has occurred");
            }
         }
      }
}

Exception Events
Besides trapping exceptions with a try..except or try..catch block, you may also use a global TApplication::OnException event handler to trap database exceptions. However, doing so will eliminate the ability to locally recover from the exception and possibly retry the operation or take some other course of action. There are several events in ElevateDB components that allow you to code event handlers that remove the necessity of coding try..except or try..catch blocks while still providing for local recovery. These events are as follows:

EventDescription
OnEditErrorThis event is triggered when an error occurs during a call to the TEDBTable, TEDBQuery , or TEDBStoredProc Edit method . The usual cause of an error is a row lock failure if the current session is using the pessimistic row locking protocol (the default). Please see the Inserting, Updating, and Deleting Rows topic for more information on using this event, and the Locking and Concurrency topic for more information on the ElevateDB row locking protocols.
OnDeleteErrorThis event is triggered when an error occurs during a call to the TEDBTable, TEDBQuery , or TEDBStoredProc Delete method. The usual cause of an error is a row lock failure (a row lock is always obtained before a delete regardless of the locking protocol in use for the current session). Please see the Inserting, Updating, and Deleting Rows topic for more information on using this event, and the Locking and Concurrency topic for more information on the ElevateDB row locking protocols.
OnPostErrorThis event is triggered when an error occurs during a call to the TEDBTable, TEDBQuery , or TEDBStoredProc Post method. The usual cause of an error is a constraint violation, however it can also be triggered by a row lock failure if the locking protocol for the current session is set to optimistic. Please see the Inserting, Updating, and Deleting Rows topic for more information on using this event, and the Locking and Concurrency topic for more information on the ElevateDB row locking protocols.
Image