Compaq ACMS for OpenVMS
Writing Server Procedures


Previous Contents Index

2.1.3 Initialization Procedures for Rdb Databases Using SQL

The initialization procedure for a server that uses an Rdb database attaches to the database by starting and ending a dummy transaction. Note that to attach fully to the database, you must start a transaction, store a dummy record, and roll back the transaction, as explained in Section 2.1.2.

The initialization procedure for a server using an Rdb database must declare the database accessed by the step procedures in the server. The database declaration in the initialization procedure must be the same as the database declarations in the step procedures in the server. To declare the database using SQL, use the DECLARE SCHEMA statement. Always use the DECLARE SCHEMA statement to name the database you are using before you use other statements that access the database.

In SQL, you start a transaction using the SET TRANSACTION statement. Section 2.1.3.1 describes how to specify the access mode and relations used by the step procedures in the server. If the database transaction cannot be started, log the failure in the ACMS audit trail log by calling SQL$SIGNAL, and then return the failure status to ensure that ACMS stops the server process.

Section 2.1.3.2 illustrates an initialization procedure written in COBOL that uses SQL. See the SQL documentation for more information about using SQL to access Rdb databases.

2.1.3.1 Specifying the Access Mode and Relations Used by the Server

When you start the dummy transaction in the initialization procedure, specify the access mode used by the step procedures in the server. If the procedures in the server perform only read-access transactions against the database, specify READ ONLY access when you start the transaction. Specify READ WRITE access if any step procedures also write or update records in the database.

Name all the relations used by the step procedures in the server to cause Rdb to read in the metadata for those relations when you start the transaction. For each relation, specify READ access if the procedures only read information from the relation. Otherwise, specify WRITE access if any of the procedures write or update records in the relation.

The following example illustrates starting a dummy transaction in an initialization procedure using COBOL and SQL. The step procedures used in the server both read and write information in the database, so the transaction is started using READ WRITE mode. The step procedures in the server access records in the RESERVATIONS, VEHICLES, VEHICLE_RENTAL_HISTORY, SITES, and REGIONS relations. The procedures both read and write records in the RESERVATIONS, VEHICLES and VEHICLE_RENTAL_HISTORY relations, so they are accessed using WRITE mode. However, the procedures only read records in the SITES and REGIONS relations, so they are accessed using READ mode.


        EXEC SQL 
                SET TRANSACTION READ WRITE 
                RESERVING 
                    reservations, vehicles, vehicle_rental_history 
                        FOR SHARED WRITE, 
                    sites, regions 
                        FOR SHARED READ 
        END-EXEC. 

The following example illustrates how to start the same dummy transaction using BASIC and RDO.


        &RDB& START_TRANSACTION READ_WRITE 
        &RDB&   RESERVING 
        &RDB&       reservations, vehicles, vehicle_rental_history 
        &RDB&           FOR SHARED WRITE, 
        &RDB&       sites, regions 
        &RDB&           FOR SHARED READ 

2.1.3.2 Using COBOL

Example 2-1 shows the initialization procedure for the AVERTZ Vehicle Rental Application Update Server. The procedure names the database used by the server using the DECLARE SCHEMA statement in the Working-Storage Section:


DATA DIVISION. 
WORKING-STORAGE SECTION. 
    . 
    . 
EXEC SQL 
DECLARE EXTERNAL SCHEMA FILENAME AVERTZ_DATABASE:VEHICLE_RENTALS 
END-EXEC. 

The procedure uses the SET TRANSACTION statement to start the dummy transaction. READ WRITE access is used because the server read, writes, and updates records in the VEHICLE_RENTALS database. The procedure names each relation used by the server in the RESERVING clause. A dummy record is stored in the RESERVATIONS relation using the INSERT statement. Finally, the procedure uses the ROLLBACK statement to end the dummy transaction and delete the dummy record. If an error occurs, the procedure sets the return status to the error status returned by Rdb, logs an error in the ACMS audit trail log by calling SQL$SIGNAL, and then returns.

Example 2-1 SQL Initialization Procedure

IDENTIFICATION DIVISION. 
************************************************************** 
PROGRAM-ID. VR-UPDATE-INIT. 
*                                                            * 
*               Version:        01                           * 
*               Edit:           00                           * 
*               Edit dates:     03-JUL-90                    * 
*               Authors:        DIGITAL                      * 
*                                                            * 
************************************************************** 
 
************************************************************** 
*         F U N C T I O N A L   D E S C R I P T I O N        * 
*                                                            * 
*  This procedure is the initialization procedure for the    * 
*  AVERTZ update server. It is used to the open the          * 
*  vehicle rental database.                                  * 
*                                                            * 
************************************************************** 
ENVIRONMENT DIVISION. 
CONFIGURATION SECTION. 
************************************************************** 
DATA DIVISION. 
************************************************************** 
 
 
WORKING-STORAGE SECTION. 
* 
* Return status to pass to ACMS 
* 
01 RET-STAT     PIC S9(9) COMP. 
01 ZERO_RESERVATION_ID PIC S9(9) VALUE 0. 
* 
* Define the SQL return status 
* 
01 SQLCODE      PIC S9(9) COMP. 
01 RDB$MESSAGE_VECTOR EXTERNAL. 
    03 Rdb$LU_NUM_ARGUMENTS     PIC S9(9) COMP. 
    03 Rdb$LU_STATUS            PIC S9(9) COMP. 
    03 Rdb$ALU_ARGUMENTS        OCCURS 18 TIMES. 
        05 Rdb$LU_ARGUMENTS     PIC S9(9) COMP. 
 
* 
* Declare the database. 
* 
EXEC SQL 
DECLARE EXTERNAL SCHEMA FILENAME AVERTZ_DATABASE:VEHICLE_RENTALS 
END-EXEC. 
 
 
*********************************************************** 
PROCEDURE DIVISION GIVING RET-STAT. 
*********************************************************** 
MAIN SECTION. 
 
000-OPEN_DB. 
 
* 
* Start a recovery unit to force Rdb to bind to the database and read 
* in the metadata for the specified relations used by this server. 
* 
        EXEC SQL 
                SET TRANSACTION READ WRITE 
                RESERVING 
                    RESERVATIONS, VEHICLES, VEHICLE_RENTAL_HISTORY 
                        FOR SHARED WRITE, 
                    SITES, REGIONS 
                        FOR SHARED READ 
        END-EXEC. 
        IF SQLCODE < ZERO 
        THEN 
            MOVE RDB$LU_STATUS TO RET-STAT 
            CALL "SQL$SIGNAL" 
            GO TO 100-EXIT-PROGRAM 
        END-IF. 
 
 
* 
* Force Rdb to create the .RUJ file for this server by inserting a 
* dummy record into the reservations relation. 
* 
        EXEC SQL 
                INSERT INTO RESERVATIONS 
                      ( 
                       RESERVATION_ID 
                      ) 
               VALUES ( 
                       :ZERO_RESERVATION_ID 
                      ) 
        END-EXEC. 
        IF SQLCODE < ZERO 
        THEN 
            MOVE RDB$LU_STATUS TO RET-STAT 
            CALL "SQL$SIGNAL" 
            GO TO 100-EXIT-PROGRAM 
        END-IF. 
 
 
* 
* Roll back the recovery unit, deleting the dummy record. 
* 
        EXEC SQL 
                ROLLBACK 
        END-EXEC. 
        IF SQLCODE < ZERO 
        THEN 
            MOVE RDB$LU_STATUS TO RET-STAT 
            CALL "SQL$SIGNAL" 
            GO TO 100-EXIT-PROGRAM 
        END-IF. 
 
        SET RET-STAT TO SUCCESS. 
 
100-EXIT-PROGRAM. 
        EXIT PROGRAM. 

2.1.4 Initialization Procedures for Rdb Databases Using RDO

The initialization procedure for a server that uses an Rdb database attaches to the database by starting and ending a dummy transaction. Note that to attach fully to the database, you must start a transaction, store a dummy record, and roll back the transaction, as explained in Section 2.1.2.

The initialization procedure for a server using an Rdb database must name the database accessed by the step procedures in the server. The database declaration in the initialization procedure must be the same as the database declarations in the step procedures in the server. To declare the database using RDO, use the INVOKE DATABASE statement. For example:


&RDB& INVOKE DATABASE FILENAME "avertz_database:vehicle_rentals" 

Start the dummy database transaction by using the START_TRANSACTION statement, which causes Rdb to attach to the database. See Section 2.1.3.1 for information on how to specify the access mode and relations that are used by the server when you start the transaction. If the step procedures in the server write or modify records in the database, use the STORE statement to write a dummy record to the database to force Rdb to create an .RUJ file. Finally, use the ROLLBACK statement to end the dummy transaction and delete the dummy record.

If an error occurs, log the failure in the ACMS audit trail log by signaling the error information in the RDB$MESSAGE_VECTOR array using the LIB$CALLG and LIB$SIGNAL OpenVMS RTL services; then return the failure status to ensure that ACMS stops the server process. For more information on signaling Rdb errors, refer to the Rdb documentation.

Example 2-2 shows the complete BASIC version of the initialization procedure for a server that uses an Rdb database with RDO. This example also illustrates how storing a dummy record forces RDB to create the .RUJ file for the server process. In this case, the ROLLBACK statement is used to end the database transaction and delete the dummy record.

Example 2-2 BASIC Initialization Procedure for Rdb Server

    FUNCTION LONG vr_update_init 
    !+ 
    ! Update server initialization procedure. 
    !- 
 
 
    !+ 
    ! Declare database. 
    !- 
    &RDB& INVOKE DATABASE FILENAME "avertz_database:vehicle_rentals" 
 
 
    !+ 
    ! Declare OpenVMS RTL routines. 
    !- 
    EXTERNAL LONG FUNCTION  LIB$SIGNAL,                         & 
                            LIB$CALLG 
 
 
    !+ 
    ! Start a database transaction to force Rdb to attach to 
    ! the database and read in the metadata for the specified 
    ! relations used by this server. 
    !- 
    &RDB& START_TRANSACTION READ_WRITE 
    &RDB&   RESERVING 
    &RDB&       reservations, vehicles, vehicle_rental_history 
    &RDB&           FOR SHARED WRITE, 
    &RDB&       sites, regions 
    &RDB&           FOR SHARED READ 
    &RDB&   ON ERROR 
                CALL LIB$CALLG( Rdb$MESSAGE_VECTOR,             & 
                                LOC( LIB$SIGNAL ) BY VALUE ) 
                EXIT FUNCTION Rdb$LU_STATUS 
    &RDB&   END_ERROR 
 
 
    !+ 
    ! Force Rdb to create the .RUJ file for this server by 
    ! inserting a dummy record into the RESERVATIONS relation. 
    !- 
    &RDB& STORE r IN reservations USING 
    &RDB&   ON ERROR 
                CALL LIB$CALLG( Rdb$MESSAGE_VECTOR,             & 
                                LOC( LIB$SIGNAL ) BY VALUE ) 
                EXIT FUNCTION Rdb$LU_STATUS 
    &RDB&   END_ERROR 
    &RDB&   r.RESERVATION_ID = "00000000" 
    &RDB& END_STORE 
 
 
    !+ 
    ! Roll back the database transaction, deleting the dummy record. 
    !- 
    &RDB& ROLLBACK 
    &RDB&   ON ERROR 
                CALL LIB$CALLG( Rdb$MESSAGE_VECTOR,             & 
                                LOC( LIB$SIGNAL ) BY VALUE ) 
                EXIT FUNCTION Rdb$LU_STATUS 
    &RDB&   END_ERROR 
 
 
    !+ 
    ! Set return status to success and return. 
    !- 
    vr_update_init = 1% 
    END FUNCTION 

2.1.5 Initialization Procedures for DBMS Databases

The initialization procedure for a server that uses a DBMS database binds to the database by starting and ending a dummy transaction. Note that to bind fully to the database, you must start a transaction, store a dummy record, and roll back the transaction, as explained in Section 2.1.2.

The initialization procedure for a server using a DBMS database must name the database accessed by the step procedures in the server. The database declaration in the initialization procedure must be the same as the database declarations in the step procedures in the server.

Start the dummy database transaction by using the READY statement, which causes DBMS to attach to the database. If the step procedures in the server write or modify records in the database, use the STORE statement to write a dummy record to the database to force DBMS to create an .RUJ file. Finally, use the ROLLBACK statement to end the dummy transaction and delete the dummy record. If an error occurs, log the failure in the ACMS audit trail log by signaling the error information using DBM$SIGNAL; then return the failure status to ensure that ACMS stops the server process.

Note

If you create the database with the OPEN=MANUAL attribute, you must open the database manually using the DBO/OPEN command before a server process can access it. Opening a database manually may also be more efficient even if you create the database with the OPEN=AUTOMATIC attribute. For more information on the DBO/OPEN command, refer to the DBMS documentation.

2.1.5.1 Using COBOL

The initialization procedure for a server using a DBMS database must identify the database the server uses. You do this by naming the schema and subschema in the database in the Data Division. For example:


DATA DIVISION. 
 
SUB-SCHEMA SECTION. 
 
DB  DEFAULT_SUBSCHEMA 
    WITHIN "PERS_CDD.PERSONNEL_SCHEMA" 
    FOR "PERS_DB:PERSONNEL". 

The subschema named---in this case, the default subschema for the PERSONNEL database---must be the same used by the step procedures in the server. You can use more than one database or subschema at a time. However, this manual discusses the use of only one subschema for a server.

If any errors occur in binding to the database, trap the error in the Declaratives section, and use the DBM$SIGNAL routine to return a fatal error status to the server process:


WORKING-STORAGE SECTION. 
 
01  status_result               PIC S9(5) COMP. 
 
PROCEDURE DIVISION GIVING status_result. 
 
DECLARATIVES. 
DML-FAILURE SECTION. 
    USE FOR DB-EXCEPTION. 
010-DBM-FAILURE. 
    MOVE DB-CONDITION TO status_result. 
    CALL "DBM$SIGNAL". 
    EXIT PROGRAM. 
END DECLARATIVES. 

Start the dummy database transaction by using the READY statement, which causes DBMS to bind to the database. If the step procedures in the server write or modify records in the database, use the STORE statement to write a dummy record to the database to force DBMS to create an .RUJ file. Finally, use the ROLLBACK statement to end the dummy transaction and delete the dummy record. For example:


MAIN SECTION. 
 
000-start. 
    SET status_result TO SUCCESS. 
 
    READY CONCURRENT UPDATE. 
    MOVE "000000" TO emp_badge_number. 
    STORE employee_record. 
    ROLLBACK. 

If you do not end the database transaction in the initialization procedure, the first procedure that uses this server fails with a DBM$_ALLREADY error.

Example 2-3 shows the complete COBOL version of the initialization procedure for a server that accesses a DBMS database. This example also illustrates how storing a dummy record forces DBMS to create the .RUJ file for the server process. In this case, the ROLLBACK statement is used to end the database transaction and delete the dummy record.

Example 2-3 COBOL Initialization Procedure for DBMS

IDENTIFICATION DIVISION. 
PROGRAM-ID. pers_upd_server_init_proc. 
 
ENVIRONMENT DIVISION. 
 
DATA DIVISION. 
SUB-SCHEMA SECTION. 
 
DB  DEFAULT_SUBSCHEMA 
    WITHIN "PERS_CDD.PERSONNEL_SCHEMA" 
    FOR "PERS_DB:PERSONNEL". 
 
WORKING-STORAGE SECTION. 
 
01  status_result               PIC S9(5) COMP. 
 
PROCEDURE DIVISION GIVING status_result. 
 
DECLARATIVES. 
DML-FAILURE SECTION. 
    USE FOR DB-EXCEPTION. 
010-DBM-FAILURE. 
    MOVE DB-CONDITION TO status_result. 
    CALL "DBM$SIGNAL". 
    EXIT PROGRAM. 
END DECLARATIVES. 
 
 
MAIN SECTION. 
 
000-start. 
    SET status_result TO SUCCESS. 
 
    READY CONCURRENT UPDATE. 
    MOVE "000000" TO emp_badge_number. 
    STORE employee_record. 
    ROLLBACK. 
 
999-end. 
    EXIT PROGRAM. 

2.1.5.2 Using BASIC

The initialization procedure for a server using a database using DBMS DML must identify the database the server uses. You do this by naming the schema and subschema in the database using the INVOKE statement. For example:


    # INVOKE DEFAULT_SUBSCHEMA - 
             WITHIN PERS_CDD.PERSONNEL_SCHEMA - 
             FOR PERS_DB:PERSONNEL - 
             ( RECORDS ) 

Start the dummy transaction using the READY statement. Use the STORE statement to write a dummy record to the database, and then end the transaction using a ROLLBACK statement to delete the dummy record. For example:


    # READY CONCURRENT UPDATE 
    employee_record::emp_badge_number = "000000" 
    # STORE employee_record 
    # ROLLBACK 

Example 2-4 illustrates a complete BASIC initialization procedure for a server that accesses a DBMS database. No error handling is necessary in this procedure because DBMS DML always signals a fatal OpenVMS error status when it detects an error condition.

Example 2-4 BASIC Initialization Procedure for DBMS

    FUNCTION LONG pers_upd_server_init_proc 
 
    %INCLUDE "pers_files:pers_common_defns" 
 
    # INVOKE DEFAULT_SUBSCHEMA - 
             WITHIN PERS_CDD.PERSONNEL_SCHEMA - 
             FOR PERS_DB:PERSONNEL - 
             ( RECORDS ) 
 
 
    pers_upd_server_init_proc = persmsg_success 
 
    # READY CONCURRENT UPDATE 
    employee_record::emp_badge_number = "000000" 
    # STORE employee_record 
    # ROLLBACK 
 
    END FUNCTION 

2.1.6 Initialization Procedures for RMS Files

An initialization procedure for a server process using RMS opens the files used by the step procedures in the server. The file definitions used in the initialization procedure must be the same as the definitions used in other procedures using those files. If you use a language that assigns channels, the channel number must also be the same in the initialization and step procedures.

If the step procedures in the server require only read access to a file, then open the file for read access only. If the step procedures in the server write to a file, then open the file for read/write access. Specify shared access if more than one server process needs access to the file.

If your step procedures need to lock multiple records in a single record stream or retain record locks after writing or updating a record, you must specify explicit lock control when you open a file.

2.1.6.1 Using COBOL

You name the files used by the procedures in the server in the Environment and Data Divisions. For example, the procedures that run in server PERS_UPD_SERVER use the Employee and History files:


ENVIRONMENT DIVISION. 
 
INPUT-OUTPUT SECTION. 
FILE-CONTROL. 
SELECT  emp_file 
        ORGANIZATION INDEXED 
        ACCESS RANDOM 
        ASSIGN TO "emp_file:employee.dat". 
 
 
SELECT  hist_file 
        ORGANIZATION INDEXED 
        ACCESS RANDOM 
        ASSIGN TO "hist_file:history.dat". 
 
I-O-CONTROL. 
APPLY LOCK-HOLDING ON emp_file, 
                      hist_file. 
 
 
DATA DIVISION. 
 
FILE SECTION. 
FD      emp_file 
        EXTERNAL 
        DATA RECORD IS employee_record 
        RECORD KEY emp_badge_number OF employee_record. 
COPY "pers_cdd.employee_record" FROM DICTIONARY. 
 
FD      hist_file 
        EXTERNAL 
        DATA RECORD IS history_record 
        RECORD KEY hist_badge_number OF history_record. 
COPY "pers_cdd.history_record" FROM DICTIONARY. 

The step procedures in the server PERS_UPD_SERVER use explicit record locking; therefore, the initialization procedure specifies the LOCK-HOLDING statement:


I-O-CONTROL. 
APPLY LOCK-HOLDING ON emp_file, 
                      hist_file. 

If you declare a file-status variable using the FILE-STAT clause in the SELECT statement, define the variable in the Working-Storage Section. For example:


WORKING-STORAGE SECTION. 
01  file-status                 PIC XX IS EXTERNAL. 

In the following example, the GIVING clause of the Procedure Division header specifies STATUS_RESULT as the procedure's return-status variable. If the initialization procedure traps any errors while trying to open the Employee and History files, it signals the RMS STS and STV error codes, moves the RMS error status into the STATUS_RESULT variable, and exits.


WORKING-STORAGE SECTION. 
 
01  status_result               PIC S9(5) COMP. 
 
PROCEDURE DIVISION GIVING status_result. 
 
DECLARATIVES. 
employee_file SECTION. 
    USE AFTER STANDARD ERROR PROCEDURE ON emp_file. 
employee_file_handler. 
        CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF emp_file, 
                                BY VALUE RMS-STV OF emp_file. 
        MOVE RMS-STS OF emp_file TO status_result. 
        EXIT PROGRAM. 
 
history_file SECTION. 
    USE AFTER STANDARD ERROR PROCEDURE ON hist_file. 
history_file_handler. 
        CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF hist_file, 
                                BY VALUE RMS-STV OF hist_file. 
        MOVE RMS-STS OF hist_file TO status_result. 
        EXIT PROGRAM. 
END DECLARATIVES. 

The initialization procedure initializes the STATUS_RESULT variable to success, and then opens the Employee and History files. Because other processes need to access the files, the procedure specifies the ALLOWING ALL clause.


MAIN SECTION. 
 
000-start. 
    SET status_result TO SUCCESS. 
 
    OPEN I-O emp_file ALLOWING ALL. 
    OPEN I-O hist_file ALLOWING ALL. 
 
999-end. 
    EXIT PROGRAM. 

See the COBOL documentation for more information on using RMS files with COBOL.

Example 2-5 shows the complete COBOL initialization procedure.

Example 2-5 COBOL Initialization Procedure for RMS Server

IDENTIFICATION DIVISION. 
PROGRAM-ID. pers_upd_server_init_proc. 
 
ENVIRONMENT DIVISION. 
 
 
INPUT-OUTPUT SECTION. 
FILE-CONTROL. 
SELECT  emp_file 
        ORGANIZATION INDEXED 
        ACCESS RANDOM 
        ASSIGN TO "emp_file:employee.dat". 
 
 
SELECT  hist_file 
        ORGANIZATION INDEXED 
        ACCESS RANDOM 
        ASSIGN TO "hist_file:history.dat". 
 
 
I-O-CONTROL. 
APPLY LOCK-HOLDING ON emp_file, 
                      hist_file. 
 
DATA DIVISION. 
 
FILE SECTION. 
FD      emp_file 
        EXTERNAL 
        DATA RECORD IS employee_record 
        RECORD KEY emp_badge_number OF employee_record. 
COPY "pers_cdd.employee_record" FROM DICTIONARY. 
 
FD      hist_file 
        EXTERNAL 
        DATA RECORD IS history_record 
        RECORD KEY hist_badge_number OF history_record. 
COPY "pers_cdd.history_record" FROM DICTIONARY. 
 
 
WORKING-STORAGE SECTION. 
 
01  status_result               PIC S9(5) COMP. 
 
PROCEDURE DIVISION GIVING status_result. 
 
 
DECLARATIVES. 
employee_file SECTION. 
    USE AFTER STANDARD ERROR PROCEDURE ON emp_file. 
employee_file_handler. 
        CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF emp_file, 
                                BY VALUE RMS-STV OF emp_file. 
        MOVE RMS-STS OF emp_file TO status_result. 
        EXIT PROGRAM. 
history_file SECTION. 
    USE AFTER STANDARD ERROR PROCEDURE ON hist_file. 
history_file_handler. 
        CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF hist_file, 
                                BY VALUE RMS-STV OF hist_file. 
        MOVE RMS-STS OF hist_file TO status_result. 
        EXIT PROGRAM. 
END DECLARATIVES. 
 
 
MAIN SECTION. 
 
000-start. 
    SET status_result TO SUCCESS. 
 
    OPEN I-O emp_file ALLOWING ALL. 
    OPEN I-O hist_file ALLOWING ALL. 
 
999-end. 
    EXIT PROGRAM. 


Previous Next Contents Index