[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

Compaq ACMS for OpenVMS
Writing Server Procedures


Previous Contents Index

3.4.1.3 Using Hard-Coded Messages in the Form

Using this method, you return a status indicator that is processed by the form in a field in a user-defined workspace. See Section 3.3.2 for more information on returning status in a field in a user-defined workspace.

The advantage of this method is that you do not need to use message files or OpenVMS system services or RTL routines to return error messages to users. The disadvantage is that you must always modify the form if you need to change the format of an error message.

To use hard-coded messages in the form, follow these steps:

  1. Define a field in a user-defined workspace to hold the status indicator. For example:


    step_status           DATATYPE TEXT 8.
    
  2. In the step procedure, return a status indicator in the STEP_STATUS field in the user-defined workspace.
    For example, in COBOL:


    MOVE "DUPLICAT" TO step_status OF task_control.
    GO TO 999-end.
    

    For example, in BASIC:


    task_ctrl_wksp::step_status = "DUPLICAT"
    EXIT FUNCTION
    
  3. In the task definition, check the status indicator field in the user-defined workspace.
    If the step procedure returns a failure indicator, then go to an exchange step that uses a form to display an error message based on the status indicator returned by the step procedure. For example:


    PROCESSING
        WORK IS
            CALL pers_add_employee_proc USING
                        task_control,
                        employee_record
        ACTION IS
            IF ( task_control.step_status <> "SUCCESS" )
            THEN
                GOTO STEP get_new_employee_data;
            END IF;
    

3.4.1.4 Using Hard-Coded Messages in the Step Procedure

Using this method, you construct the complete error message directly in the step procedure. You use literal message text stored in the procedure, formatting variable error messages, if necessary.

The advantage of this method is that you do not need to use message files or OpenVMS system services or RTL routines to return error messages to users. The disadvantage is that you must always modify and recompile the step procedure and relink the procedure server image if you need to change the format of an error message.

To use hard-coded messages in a step procedure, follow these steps:

  1. Define a field in a user-defined workspace to hold the error message text. For example:


    task_status_msg       DATATYPE TEXT 80.
    
  2. In the step procedure, construct the error message in the message text field.
    The following example in COBOL formats an error message and then returns a failure status to the task:


    *
    * Format 'Employee already exists' error message.
    *
        MOVE SPACES TO task_status_msg.
        STRING "Employee ID: " DELIMITED BY SIZE
                emp_badge_number DELIMITED BY " "
                " (last name: " DELIMITED BY SIZE
                emp_last_name DELIMITED BY " "
                ") already exists on file" DELIMITED BY SIZE
        INTO    task_status_msg.
        SET status-result TO FAILURE.
        GO TO 999-end.
    

    The following example in BASIC formats an error message and then returns a failure status to the task:


    !
    ! Format 'Employee already exists' error message.
    !
    task_ctl_rec::task_status_msg =                                 &
            "Employee ID: " +                                       &
            emp_rec::emp_badge_number +                             &
            " (last name: " +                                       &
            TRM$( emp_rec::emp_last_name ) +                        &
            ") already exists on file"
    EXIT FUNCTION 0
    
  3. In the task definition call to the procedure, test the ACMS$PROCESSING_STATUS workspace, and go to an exchange step that displays the error message on the form if an error occurs. For example:


    PROCESSING
        WORK IS
            CALL pers_add_employee_proc USING
                        task_control,
                        employee_record
        ACTION IS
            IF ( ACMS$T_STATUS_TYPE = "B" )
            THEN
                GOTO STEP get_new_employee_data;
            END IF;
    

3.4.2 Raising Exceptions in Step Procedures

In some cases, rather than returning errors for the action part of a step to handle, you can let the exception handler part of a step deal with errors. If your task is designed in this way, you need to raise an exception from your step procedure. ACMS supplies three services that raise different kinds of exceptions:

  • ACMS$RAISE_STEP_EXCEPTION
  • ACMS$RAISE_TRANS_EXCEPTION
  • ACMS$RAISE_NONREC_EXCEPTION

The ACMS exception services differ in an important way from the superseded ACMSAD$REQ_CANCEL service. Whereas the ACMSAD$REQ_CANCEL service immediately cancels the current task and does not return control to the step procedure, the ACMS exception services all return control to the step procedure after setting the appropriate exception condition. This allows the step procedure to clean up any context in the server and to complete normally.

Allowing the step procedure to complete before raising the exception in the task means that ACMS does not have to interrupt the server process. Therefore, if a step procedure uses one of the exception services to raise an exception, and you have specified that your server is to be run down on cancel only if it is interrupted, ACMS does not need to run down the server process. See Section 2.3 for details on how to specify when ACMS should run down your server.

Because step exceptions, transaction exceptions, and nonrecoverable exceptions are not raised in the task until the step procedure completes, have the step procedure return as soon as possible after raising an exception.

Note

For all servers, Compaq recommends specifying that ACMS run down the server only if it is interrupted. Using this attribute does not, however, change the effect of using the ACMSAD$REQ_CANCEL service. Because the ACMSAD$REQ_CANCEL service causes the server to be interrupted, ACMS runs down the server in this situation. For this reason, use ACMS$RAISE_NONREC_EXCEPTION instead of ACMSAD$REQ_CANCEL.

3.4.2.1 Raising Recoverable Exceptions in Step Procedures

You can handle task execution errors in the exception handler part of a step, as explained in Compaq ACMS for OpenVMS Writing Applications. This manual discusses how to raise exceptions only in step procedures.

Step procedures can raise the following recoverable exceptions:

  • Step exception
  • Transaction exception

Following are explanations and examples of the two ACMS services that step procedures use to raise recoverable exceptions.

  • ACMS$RAISE_STEP_EXCEPTION
    A step procedure raises a step exception by calling this service. You call this service to raise an exception that can be handled by the exception handler part of the processing step or an outer-block step. A step procedure might raise a step exception if, for example, a procedure called from a processing step in a nested block detects an error condition that must be handled by the exception handler on the outer block step.
    The following example shows the COBOL code in the error-handling section of a procedure.


    CALL "ACMS$RAISE_STEP_EXCEPTION" USING BY REFERENCE RET-STAT.
    

  • ACMS$RAISE_TRANS_EXCEPTION
    A step procedure that is participating in a distributed transaction can use the ACMS$RAISE_TRANS_EXCEPTION service to raise a transaction exception if a resource manager returns a recoverable error---for example, a dead-lock error condition. Note that you cannot call the ACMS$RAISE_TRANS_EXCEPTION service in a step procedure that is not participating in a distributed transaction.
    When a step procedure raises a transaction exception, the exception falls under the control of the exception handler part of the transaction step or outer-block step, if one exists. The following example shows the COBOL code in a procedure that raises a transaction exception:


    SQL_ERROR_HANDLER.
    
        IF (RDB$LU_STATUS = RDB$_DEADLOCK) OR
           (RDB$LU_STATUS = RDMS$_DEADLOCK) OR
           (RDB$LU_STATUS = RDB$_LOCK_CONFLICT) OR
           (RDB$LU_STATUS = RDMS$_LCKCNFLCT) OR
           (RDB$LU_STATUS = RDMS$_TIMEOUT)
        THEN
            CALL "ACMS$RAISE_TRANS_EXCEPTION" USING
                                BY REFERENCE ACMS$_TRANSTIMEDOUT
        ELSE
            CALL "LIB$CALLG" USING
                        BY REFERENCE Rdb$MESSAGE_VECTOR,
                        BY VALUE LIB$SIGNAL
            CALL "ACMS$RAISE_NONREC_EXCEPTION" USING
                                BY REFERENCE RDB$LU_STATUS
        END-IF.
    

Chapter 9 contains reference information regarding recoverable exception services.

3.4.2.2 Raising Nonrecoverable Exceptions in Step Procedures

ACMS raises a nonrecoverable exception under the following conditions:

  • A fatal OpenVMS exception condition generated by the procedure
    ACMS raises a nonrecoverable exception if a step procedure generates a fatal exception. For example, if you use the the OpenVMS RTL service LIB$STOP to signal an error, or if an exception is raised by the hardware (perhaps as the result of an access violation), then ACMS raises a nonrecoverable exception and cancels the task.

    Note

    ACMS always runs down a server process if a step procedure generates a fatal OpenVMS exception condition.
  • A call to ACMS$RAISE_NONREC_EXCEPTION
    A step procedure calls this programming service when an error occurs from which neither the step procedure nor the task can recover. When a step procedure calls this service, ACMS raises a nonrecoverable exception and unconditionally cancels the current task.
    You call the ACMS$RAISE_NONREC_EXCEPTION service as you do any OpenVMS run-time service, by using a CALL statement in COBOL, for example. No arguments are required in the call. You can, however, include an optional argument describing the reason for the cancellation. The argument is a read-only longword, passed by reference.
    The following example shows the COBOL code in a procedure that raises a nonrecoverable exception.


    CALL "ACMS$GET_TID" USING CS-TID GIVING ret-stat.
    IF ret-stat IS NOT SUCCESS
    THEN
        CALL "ACMS$RAISE_NONREC_EXCEPTION" USING ret-stat.
        GO TO 999-end.
    

    Chapter 9 contains reference information regarding the nonrecoverable exception service.

3.5 Performing Terminal I/O from a Procedure Server

One of the major advantages of implementing an application with ACMS is that you can easily separate your terminal I/O from your database I/O by performing all terminal I/O in exchange steps and all database I/O in processing steps. Following these guidelines has many advantages; two of the major ones are better performance and the ability to distribute tasks over multiple nodes.

Application developers find, however, that some situations require them to do terminal I/O in a processing step---for example, if they are incorporating an existing program into an application. Sometimes it is simpler to make an existing program a single-step task that does terminal I/O than to convert the program to a multiple-step task, which requires removing the terminal I/O from the program and placing it in exchange steps. For this reason, although it is not recommended, ACMS supports doing terminal I/O from processing steps. This section describes the limitations and restrictions involved.

ACMS does not automatically associate a terminal channel with the server process. If a procedure is to do terminal I/O, it must open and close the channel it uses each time it is called. The terminal channel cannot be retained across processing steps, even if the task retains server context. If the procedure does not close the channel before it completes, ACMS cancels the task and runs down the server process.

For a server process to perform terminal I/O, the task must pass the terminal to that process. In single-step tasks, the default is to pass the terminal to the server process. In multiple-step tasks, however, the default is not to pass the terminal to the server process, regardless of whether the server is a DCL server or a procedure server.

In multiple-step tasks, therefore, the task definition must use the TERMINAL I/O phrase for any processing step that does terminal I/O. (When used as an attribute on a processing step, TERMINAL I/O and REQUEST I/O are equivalent; however, REQUEST I/O as a processing step attribute is a declining feature and is, therefore, discouraged.)

Note

Because distributed tasks cannot perform terminal I/O in processing steps, you cannot distribute a task that contains TERMINAL I/O (or REQUEST I/O) syntax in a processing step of the task definition.

Because the procedure must open and close the terminal channel, there are several restrictions on the kinds of statements used for terminal I/O from a procedure server. Keep in mind the following considerations:

  • A procedure that does terminal I/O must open the terminal channel it uses; the channel cannot be opened in the initialization procedure.
  • You can use any terminal I/O calls that allow you to open a terminal channel explicitly. Two examples of these are the DECforms FORMS$ENABLE and the TDMS TSS$OPEN services.
  • Do not use programming statements such as DISPLAY and ACCEPT in COBOL, or INPUT and PRINT in BASIC.
  • Do not use the OpenVMS LIB$GET_INPUT and LIB$PUT_OUTPUT services.
  • Do not use the RTL screen management services.
  • Provide a cancel procedure for the server handling the procedure. It is recommended that the cancel procedure either close any open terminal channel when the task is canceled or allow the server process to run down when the task is canceled.


Chapter 4
Accessing Resource Managers

This chapter explains how to write step procedures that access several of the resource managers you can use with ACMS applications: Rdb using SQL, and Rdb using RDO, DBMS, and RMS.

The primary example in the chapter shows how to access an Rdb database using SQL with a procedure that participates in a distributed transaction. Examples showing how to access other resource managers supported by ACMS with distributed transactions are partial; they contain only syntax that is different from the SQL example.

The COBOL step procedure that is the principal example in this chapter is part of the AVERTZ Sample Application. The step procedure VR_COMPLETE_CHECKOUT_PROC participates in a distributed transaction that starts and ends in the parent task. Figure 4-1 shows where VR_COMPLETE_CHECKOUT_PROC fits into the AVERTZ Sample Application. The figure shows the ACMS menu, from which users can select the Reservation Task or the Checkout Task as two of three tasks displayed on the menu. Both the Reservation Task and the Checkout Task can call the Complete Checkout Task, which, in turn, calls the procedure VR_COMPLETE_CHECKOUT_PROC.

See Compaq ACMS for OpenVMS Concepts and Design Guidelines for a description of the AVERTZ sample application and Compaq ACMS for OpenVMS Writing Applications for a description of VR_COMPLETE_CHECKOUT_TASK. For further explanation of VR_COMPLETE_CHECKOUT_PROC. see Section 4.1.

Figure 4-1 Calling the Procedure VR_COMPLETE_CHECKOUT_PROC


4.1 Using SQL with Rdb

This section describes how to write step procedures using the Structured Query Language (SQL) interface to Rdb. The techniques used with SQL are similar to those used in developing tasks and server procedures using Relational Data Manipulation Language (RDML), developed by Digital Equipment Corporation.

See the SQL documentation for general information regarding SQL.

The main example in this chapter, shown in Example 4-7, is a COBOL step procedure called VR_COMPLETE_CHECKOUT_PROC, which accesses an Rdb database using SQL. The procedure is part of the AVERTZ sample application.

Example 4-1 is part of the Complete Checkout Task, which calls the procedure VR_COMPLETE_CHECKOUT_PROC in the AVERTZ Sample Application. When checking out a car, the customer has the option of canceling the reservation. If the customer chooses to cancel the reservation, the task calls a procedure to perform the cancel processing. Otherwise, the task calls a procedure to complete the reservation. The task definition, in a simplified version, performs the following steps, which are also numbered in the example.

  1. If the customer chooses to check out the car, the task calls the procedure VR_COMPLETE_CHECKOUT_PROC to complete the checkout process.
  2. If the customer cancels the reservation, the task calls the procedure VR_CANCEL_RS_PROC to cancel the reservation.
  3. The task calls another procedure, VR_WRITE_HIST_RECORD_PROC, which writes the completion of the checkout or the cancellation to the database.

Example 4-1 Task Definition that Calls Server Procedures Using SQL


REPLACE TASK avertz_cdd_task:vr_complete_checkout_task

USE WORKSPACES vr_control_wksp,
.
.
.
TASK ARGUMENTS ARE vr_sendctrl_wksp     WITH ACCESS READ,
.
.
.
BLOCK WORK WITH TRANSACTION
                     NO I/O

!
perform:
!+
!-
! Perform the checkout process or cancel the reservation depending
! on the user's choice.
!

     PROCESSING
        SELECT FIRST TRUE
                (vr_control_wksp.ctrl_key = "OK"):
                     (1) CALL PROCEDURE    vr_complete_checkout_proc
                        IN      vr_update_server
                        USING   vr_reservations_wksp,
                                vr_vehicles_wksp,
                                vr_control_wksp;
                (vr_control_wksp.ctrl_key = "CANCL"):
                     (2) CALL PROCEDURE     vr_cancel_rs_proc
                        IN      vr_update_server
                        USING   vr_reservations_wksp,
                                vr_control_wksp;
        END SELECT;

  .
  .
  .
! Write to the history record to record the completion of the checkout or the
! the cancellation of the reservation.
!
     PROCESSING
     (3) CALL PROCEDURE        vr_write_hist_record_proc
        IN      vr_log_server
        USING   vr_hist_wksp,
                vr_reservations_wksp;

      .
      .
      .
!
END BLOCK;
!
END DEFINITION;

4.1.1 Using Embedded SQL Statements in Step Procedures

When using embedded SQL statements in step procedures, follow these guidelines:

  • Begin each statement with the EXEC SQL flag.
  • Remember that the EXEC SQL flag can occur at the beginning of only the first line of a multiline SQL statement. Follow the rules of the programming language you are using to continue SQL statements from one line to the next.
  • Regardless of the rules of the language you are using for parameter names, specify underscores rather than hyphens when entering names of database entities.
  • In COBOL, flag the end of an SQL statement with the END-EXEC keyword. Place a period after END-EXEC if a COBOL statement in the same position requires a period.

Example 4-2 contains examples illustrating each of these guidelines.

For other high-level languages, the rules for beginning and ending SQL statements in step procedures vary. See the SQL documentation for more information about beginning and ending SQL statements in step procedures.

Before you can use SQL to access a database, you must declare the database. You do this in each server procedure that accesses the database. If you are using COBOL, name the Rdb database in the Working-Storage Section of the Data Division of your procedure using the DECLARE SCHEMA statement. This must appear in the procedure before you can use other SQL statements to reference data in the database.

Example 4-2 shows the DECLARE SCHEMA statement used in the procedure VR_COMPLETE_CHECKOUT_PROC to declare the database. (Example 4-7 contains the complete procedure.)

Example 4-2 Declaring the Database


************************************************************
DATA DIVISION.
************************************************************
WORKING-STORAGE SECTION.
*
*  Return status to pass to ACMS
*
01 RET-STAT      PIC S9(9) COMP.
01 RSTAT         PIC S9(9) COMP.

.
.
.
*
*  Declare the database schema.
*
EXEC SQL
   DECLARE EXTERNAL SCHEMA FILENAME AVERTZ_DATABASE:VEHICLE_RENTALS
END-EXEC.

4.1.2 Using SQL with Distributed Transactions

When you use SQL with a distributed transaction, you must pass the transaction ID (TID) to SQL on each executable DML verb using an SQL context structure.

This section describes how to:

  • Define an SQL context structure
  • Obtain the TID and store it in the context structure
  • Pass the context structure to SQL using embedded SQL and SQL module language.

See Example 4-7 for a complete example of using precompiled SQL in a distributed transaction using COBOL. See the SQL documentation for information on how to define and use an SQL context structure.


Previous Next Contents Index