Release 10.1A: OpenEdge Development:
Progress Dynamics Basic Development

> ## Transaction scoping within procedures

> Progress provides sophisticated rules within the 4GL to manage database transactions for a variety of situations controlled by the definition of table buffers, blocks of executable code, and other factors. These rules have been effective in supporting complex procedures for character-mode applications running in a host-based or client/server environment, in which the user interface definition and the application logic are often heavily intertwined. However, such complex blocks of database-related logic can be problematic when used in a distributed environment such as that managed by Progress Dynamics. In general, the best rule for managing transactions in a distributed environment is to keep the transaction as small in scope as possible. Also, to keep the definition of the transaction block as simple and unambiguous as possible, avoid unanticipated transaction scoping effects.

> If you write logic to be executed within the context of one of the standard SDO or SBO validation procedures, then the database transaction is managed for you. The transaction block is started before the `beginTransactionValidate` procedures execute and ended after the `endTransactionValidate` procedures. You do not need to define a transaction block within those procedures.

> If you are writing procedures for PLIPs to be executed outside these boundaries, however, you must manage the transaction scope yourself. Again, keep the transaction definition simple and unambiguous to avoid errors. Here are some basic guidelines:

> - Define the transaction block explicitly within a single internal procedure, and not in the Main Block of an external procedure with internal procedures where the updates are done.

> - Define a buffer with a distinct name (such as `b``<tablename>` or `b_` `<tablename>` as the SDO logic procedure uses) for the database table to be updated, within the internal procedure where the transaction block is defined.

> - Ensure that records are strong scoped using a `DO` `FOR` block for the table buffer.

> - Scope transactions explicitly using the `TRANSACTION` keyword.

> - Always use an explicit record-locking keyword on any statement that references the database, so that the behavior of the code is clear and does not rely on defaults.

> - Avoid `SHARE-LOCK`s wherever possible, as these do not translate well to other databases supported by OpenEdgeŽ DataServers. Read the documentation and white papers on DataServers if you need to familiarize yourself with other guidelines for writing code that ports effectively to DataServers.

> - Define the `UNDO` and `LEAVE` qualifiers of the transaction block explicitly.

> - Use the `NO-ERROR` qualifier on database statements that might fail. Check the `ERROR-STATUS` or the record `AVAILABLE` state and use the Progress Dynamics messaging support to generate a meaningful application message. Write code to react to the error appropriately, rather than relying on default behavior.

> The following abbreviated example adapted from the framework code illustrates some of these points:

>     PROCEDURE updateProc:
>     DEFINE INPUT PARAMETER pcObjectName AS CHARACTER NO-UNDO.
>     DEFINE OUTPUT PARAMETER pcErrorText AS CHARACTER NO-UNDO.
>     DEFINE BUFFER bWizardTbl FOR WizardTbl.
>      tran-block:
>      DO FOR bWizardTbl TRANSACTION ON ERROR UNDO tran-block, 											LEAVE tran-block:
>       FIND FIRST bWizardTbl EXCLUSIVE-LOCK WHERE  NO-ERROR.
>       IF NOT AVAILABLE bWizardTbl THEN
>       DO:
>        ASSIGN pcErrorText = {aferrortxt.i ‘RY’ ‘2’ ‘?’ ‘?’ pcObjectName
>               “’Browser’”}.
>        UNDO tran-block, LEAVE tran-block.
>       END.  /* END NOT AVAILABLE bWizardTbl */
>     ...
>      END.   /* END tran-block TRANSACTION */
>      RETURN.
>     END PROCEDURE.

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095