Example Programs

This chapter provides and describes program examples.

1. Service Program

The following are the steps for writing a service program.

image

1.1. Example Program

The following is an example of a service program.

Since the service described in the example program uses the Tmax AUTOTRAN function in a server included in an XA server group, AUTOTRAN must be set to Y for the service in the Tmax configuration file.

<$TMAXDIR/sample/cobserver/carrayauto.pco>

        ******************************************************
        * XA service that uses a CARRAY buffer            *
        ******************************************************
        IDENTIFICATION             DIVISION.
        PROGRAM-ID.                CARRAYAUTO.
        AUTHOR.                    TMAX DEVELOPMENT.
        ENVIRONMENT                DIVISION.
        CONFIGURATION                SECTION.

        DATA                        DIVISION.
        FILE                    SECTION.

        WORKING-STORAGE        SECTION.



        ******************************************************
       * Definitions for Tmax ATMI functions
       ******************************************************
       01  TPSVCRET-REC.
           COPY TPSVCRET.
        *
        01  TPTYPE-REC.
            COPY TPTYPE.
        *
        01 TPSTATUS-REC.
            COPY TPSTATUS.
        *
        01  TPSVCDEF-REC.
            COPY TPSVCDEF.
        *
        01  TX-RETURN-STATUS.
            COPY TXSTATUS.

        ******************************************************
        * Log message definitions
        ******************************************************
        01  LOGMSG.
                05  LOGMSG-SVC    PIC X(16).
                05  FILLE            PIC X(3) VALUES " : ".
                05  LOGMSG-TEXT     PIC X(80).
        01  LOGMSG-LEN            PIC S9(9)  COMP-5.

        ******************************************************
        * User defined data records
        ******************************************************
        01 RECV-STRING            PIC X(100).
        01 SEND-STRING            PIC X(100).

        ******************************************************
        * Declarations for user-defined Oracle host variables
        ******************************************************
         EXEC SQL BEGIN DECLARE SECTION END-EXEC.
         01  S-SRC.
            05  S-TEMP            PIC X(10) VARYING.
         EXEC SQL END DECLARE SECTION END-EXEC.
            EXEC SQL INCLUDE SQLCA END-EXEC.

            LINKAGE                SECTION.
            *
            PROCEDURE                DIVISION.
            *
         000-MAIN.

            PERFORM 100-SVCSTART      THRU 100-EXIT.
            PERFORM 200-DBINSERT      THRU 200-EXIT.
            PERFORM 900-TPRETURNSCS   THRU 900-TPRETURNSCS-X.

            000-EXIT.

     ******************************************************
     * Receiving data from a client
     ******************************************************
         100-SVCSTART.
                MOVE LENGTH OF RECV-STRING TO LEN.
                CALL "TPSVCSTART" USING TPSVCDEF-REC
                                 TPTYPE-REC
                                 RECV-STRING
                                 TPSTATUS-REC.

            IF NOT TPOK
                 MOVE "TPSVCSTART Fail" TO LOGMSG-TEXT
                    PERFORM 800-USERLOG
                 PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
            END-IF.

            IF TPTRUNCATE
                    MOVE "Received data was truncated" TO LOGMSG-TEXT
                    PERFORM 800-USERLOG
                    PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
            END-IF.

        DISPLAY "------------------------------------------------".

             MOVE SERVICE-NAME TO LOGMSG-SVC.
                MOVE "Starting the service " TO LOGMSG-TEXT.
             PERFORM 800-USERLOG.
            100-EXIT.

         200-DBINSERT.
             MOVE RECV-STRING(1:LEN) TO S-TEMP-ARR.
             MOVE LENGTH OF S-TEMP-ARR TO S-TEMP-LEN.

        * Handling DB INSERT
             EXEC SQL INSERT INTO TEMP (NAME,SAL)
                     VALUES (RTRIM(:S-TEMP),150)
                END-EXEC.
                IF SQLCODE NOT = 0
                    PERFORM 800-SQLERROR
                    PERFORM 800-USERLOG
                    PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
             END-IF.

             STRING "Inserted data : " S-TEMP-ARR
                 DELIMITED BY SIZE INTO LOGMSG-TEXT.
             PERFORM 800-USERLOG.

             MOVE "Successful" TO SEND-STRING.

         200-EXIT.

            800-SQLERROR.
         * Writing log messages
                STRING "800-SQLERROR : " SQLERRMC
             DELIMITED BY SIZE INTO LOGMSG-TEXT.
             MOVE SQLCODE TO APPL-CODE.

        ******************************************************
        * Write out a log err messages
        ******************************************************
            800-USERLOG.
         DISPLAY LOGMSG.

        ******************************************************
        * The service completed successfully.
        ******************************************************
        900-TPRETURNSCS.
            MOVE "The service executed successfully." TO LOGMSG-TEXT.
            PERFORM 800-USERLOG.

            SET TPSUCCESS TO TRUE.
           MOVE LENGTH OF SEND-STRING TO LEN.
           COPY TPRETURN REPLACING
           DATA-REC BY SEND-STRING.

        900-TPRETURNSCS-X.

        ******************************************************
        * The service terminated abnormally.
        ******************************************************
        900-TPRETURNFAIL.
            MOVE "The service terminated abnormally." TO LOGMSG-TEXT.
            PERFORM 800-USERLOG.

            SET TPFAIL TO TRUE.
           MOVE "Cannot process " TO SEND-STRING.
           MOVE LENGTH OF SEND-STRING TO LEN.
           COPY TPRETURN REPLACING

             DATA-REC BY SEND-STRING.
        900-TPRETURNFAIL-X.

The following describes each step in detail.

  1. Set the service name. The service name to be used by a service caller in TPCALL is defined in PROGRAM-ID.

    PROGRAM-ID. CARRAYAUTO.
  2. Define buffers to be used to send and receive data to and from a client and a service caller.

    ******************************************************
    * User defined data records
    ******************************************************
     01 RECV-STRING            PIC X(100).
             01 SEND-STRING            PIC X(100).
  3. Start the service. Data from a service caller is saved in the defined buffer.

    In the example, data from a service caller to RECV-STRING is saved. If an error occurs, it is checked in "IF NOT TPOK". If the size of the buffer RECV-STRING is smaller than data from the service caller, the TPTRUNCATE error occurs.

    MOVE LENGTH OF RECV-STRING TO LEN.
       CALL "TPSVCSTART" USING TPSVCDEF-REC
                            TPTYPE-REC
                            RECV-STRING
                            TPSTATUS-REC.
        IF NOT TPOK
            MOVE "TPSVCSTART Fail" TO LOGMSG-TEXT
            PERFORM 800-USERLOG
            PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
        END-IF.
    
        IF TPTRUNCATE
            MOVE "Received data was truncated" TO LOGMSG-TEXT
               PERFORM 800-USERLOG
               PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
        END-IF.
  4. The service completed successfully.

        SET TPSUCCESS TO TRUE.
        MOVE LENGTH OF SEND-STRING TO LEN.
        COPY TPRETURN REPLACING
        DATA-REC BY SEND-STRING.
  5. An error is returned due to a logic error.

    TPRETURN is used to send a response to the service caller after the business logic is complete. If the service fails to execute, TPFAIL is used. If TPRETURN is called using TPFAIL, the service caller receives tperrno=11(TPESVCFAIL) in the C language or TP-STATUS=11(TPESVCFAIL) in the COBOL language as an error code.

        SET TPFAIL TO TRUE.
        MOVE "Cannot process " TO SEND-STRING.
        MOVE LENGTH OF SEND-STRING TO LEN.
        COPY TPRETURN REPLACING
        DATA-REC BY SEND-STRING.

1.2. Makefile

An executable file is created by linking a user service program with libraries provided by Tmax and the DB. The following are the steps for creating an executable file.

image

  1. *.pco → *.cob

    Precompile a ProCOBOL program.

  2. *.cob → *.o

    Create an object file by compiling a COBOL program.

  3. *.o + *.a → executable file :

    Create an executable file by linking the object file with libraries provided by Tmax and the DB.

If there is a single COBOL service and only one service exists in a server, the above 3 steps are handled in a single Makefile. However, in general, multiple services exist in a server. The first two steps must be processed for each service, while the third step is executed only once.

The first two steps are handled in a shell program, while the third step is handled in a Makefile.

$ cat carray_xa.sh
echo "-------------> carrayauto.pco"
procob18 sqlcheck=full userid=scott/tiger mode=ansi release_cursor=no
hold_cursor=yes maxliteral=160 ireclen=132 iname=carrayauto.pco

cob -C IBMCOMP -C NESTCALL -cx carrayauto.cob
echo "-------------> carraynauto.pco"
procob18 sqlcheck=full userid=scott/tiger mode=ansi release_cursor=no
hold_cursor=yes maxliteral=160 ireclen=132 iname=carraynauto.pco

cob -C IBMCOMP -C NESTCALL -cx carraynauto.cob

The following describes each step.

  1. Create a COBOL object file with a shell.

     sh carray_xa.sh
    -------------> carrayauto.pco
    Pro*COBOL: Release 1.8.76.0.0 - Production on Wed May 7 23:43:42 2003
    (c) Copyright 2001 Oracle Corporation. All rights reserved.
    System default option values taken from:
    /database/ora9/precomp/admin/pcccob.cfg
    Precompiling carrayauto.pco
    -------------> carraynauto.pco
    Pro*COBOL: Release 1.8.76.0.0 - Production on Wed May 7 23:43:42 2003
    (c) Copyright 2001 Oracle Corporation. All rights reserved.
    System default option values taken from:
    /database/ora9/precomp/admin/pcccob.cfg
    Precompiling carraynauto.pco
    1. Compilation options for procob18 and cob depend on the operating system. For more information about options for procob18, refer to $ORACLE_HOME/precomp/demo/procob/demo_procob.mk.

    2. Since carry_xa.sh precompiles and compiles carrayauto.pco and carraynauto.pco, both .pco files are required in the above example.

  2. Create the Makefile to create an executable file.

    #Makefile
    
    TARGET = carray_xa                   -----(1)
    
    TMAXCBLSTUB = cblstub                -----(2)
    TMAXCBLSTUBOBJ = $(TMAXCBLSTUB).o
    
    COBOBJS = carrayauto.o carraynauto.o -----(3)
    OBJS    = $(TMAXCBLSTUBOBJ) $(SDLOBJ) $(SVCTOBJ)
    SVCTOBJ = $(TARGET)_svctab.o
    SDLOBJ  = $(TMAXDIR)/lib/sdl.o
    
    CFLAGS  = -O -q32 -g -D_CBL_MODULE -I$(TMAXDIR) -I$(TMAXDIR)/usrinc
    LDFLAGS = -brtl
    COBFLAGS= -C IBMCOMP -C NESTCALL
    
    APPDIR  = $(TMAXDIR)/appbin
    SVCTDIR = $(TMAXDIR)/svct
    LIBDIR  = $(TMAXDIR)/lib
    LIBS    = -loras -lcbls  -----(4)
    
    ORALIBD = $(ORACLE_HOME)/lib32
    ORALIBS = $(ORACLE_HOME)/precomp/lib32/cobsqlintf.o -lclntsh  -lld -lm
              `cat $(ORACLE_HOME)/lib32/sysliblist`  -lm  -lc_r -lpthreads
    #
    .SUFFIXES : .c
    .c.o:
            $(CC) $(CFLAGS) -c $<
    # server compile
    #
    $(TARGET): $(OBJS)
            cob -Q "-brtl" $(COBFLAGS) -g -o $(TARGET) -L$(LIBDIR) -L$(ORALIBD)
                           $(OBJS) $(COBOBJS) $(LIBS) $(ORALIBS)
            mv -f $(TARGET) $(APPDIR)/.
            rm -f $(TARGET).o $(SVCTOBJ) $(TMAXCBLSTUBOBJ) $(COBOBJS)
    $(TMAXCBLSTUBOBJ):
            cc $(CFLAGS) $(LDFLAGS) -c $(TMAXDIR)/cobinc/$(TMAXCBLSTUB).c
    
    $(SVCTOBJ):$(SVCTDIR)/$(TARGET)_svctab.c
            cc $(CFLAGS) -c $(SVCTDIR)/$(TARGET)_svctab.c
    
    ################################################
    
    clean:
            -rm -f $(OBJS) core $(TARGET) $(TARGET).lis $(TARGET).cob
    Item Description

    (1) TARGET

    Specifies a server (executable file) name.

    (2) TMAXCBLSTUB

    Specifies a Tmax stub file name.

    (3) COBOBJS

    Specifies the name of an object file of a service written in COBOL.

    (4) LIBS

    Specifies a Tmax library name.

1.3. Compiling and Starting a Service

Compile the created Makefile.

$ make -f carray_xa.mk

Start the compiled server program.

$ tmboot -s carray_xa

1.4. Testing a Service Call

Use the tmd utility to test the service without writing a client program.

Test the CARRAYAUTO service using tmd_CARRAYAUTO file in the $TMAXDIR/cobclient directory.

$ cd $TMAXDIR/cobclient
$ tmd -i t md_CARRAYAUTO
output: Successful

2. Program Using the FDL Buffer

Since a COBOL service program cannot directly use an FDL buffer, the buffer structure must be converted. To use an FDL buffer and view file, pre-tasks must be completed.

Extract cobolsanple.tar. viewdemo.v in the ucblinc directory as an example view file. fdldemo.f is an example FDL file.

Fdl  : $TMAXDIR/ucblinc/fdldemo.f
View : $TMAXDIR/ucblinc/viewdemo.v

2.1. Creating FDL

Create field information to be used in a client or server.

< fdldemo.f >

# name            number            type        flags        comments
# string type
FDL_S1            1001              string        -             -
FDL_S2            1002              string        -             -

# integer type
FDL_I1            2001              int           -             -
FDL_I2            2002              int           -             -

# long type
FDL_L1            3001              long         -              -
FDL_L2            3002              long         -              -

# float type
FDL_F1            4001              float        -              -
FDL_F2            4002              float        -              -

Locate the created tmax.fdl file in the directory set in $FDLFILE specified by an environment variable.

If cobolsample.tar is used, fdldemo.f is created in the $TMAXDIR/ucblinc directory. Execute fdlc in the directory to specify $TMAXDIR/ucblinc in $FDLFILE.

$fdlc –c –i fdldemo.f –o tmax.fdl

For more information about how to use a field buffer, refer to Tmax FDL Reference Guide.

2.2. Creating a View File

Since a field buffer cannot be used in COBOL, create a view (structure/struct) and convert the data using a specific function to use field buffer data received from (or to be sent to) a requester.

< viewdemo.v >

VIEW viewdemo
#type    cname            Fldkey        count    flag    size   null
string   sdata1           FDL_S1          1        -      20    "@@"
string   sdata2           FDL_S2          5        -      20    "@@"
int      idata1           FDL_I1          1        -      -       0
int      idata2           FDL_I2          5        -      -       0
long     ldata1           FDL_L1          1        -      -       0
long     ldata2           FDL_L2          5        -      -       0
float    fdata1           FDL_F1          1        -      -       0
float    fdata2           FDL_F2          5        -      -       0
double   ddata1           FDL_D1          1        -      -       0
double   ddata2           FDL_D2          5        -      -       0
END

Locate the created tmax.sdl file in the directory set in $SDLFILE specified by an environment variable.

If cobolsample.tar is used, viewdemo.v is created in the $TMAXDIR/ucblinc directory. Execute sdlc in the directory to specify $TMAXDIR/ucblinc in $SDLFILE.

$cd $TMAXDIR/ucblinc
$ sdlc -c -v viewdemo.v -o tmax.sdl
$ ls -l
-rw-r-xr-- 1 tmax dba 382 Apr 28 17:27 viewdemo.v*
-rw-r--r-- 1 tmax dba 976 May 7 18:17 tmax.sdl

2.3. Creating a View File for COBOL

Create a view file for COBOL.

$ sdlc -C -v viewdemo.v
$ls -l total 48
total 48
drwxr-xr-x 2 tmax dba 512 Apr 30 14:48./
drwxr-xr-x 7 tmax dba 512 Apr 14 11:50 ../
-rw-r--r-- 1 tmax dba 671 Apr 30 14:48 VIEWDEMO.cbl
-rw-r-xr-- 1 tmax dba 382 Apr 28 17:27 viewdemo.v*

< VIEWDEMO.cbl >

 *        VIEWNAME: "viewdemo"
          05 SDATA1                        PIC X(20).
          05 SDATA2 OCCURS 5 TIMES         PIC X(20).
          05 IDATA1                        PIC S9(9)    USAGE IS COMP-5.
          05 IDATA2 OCCURS 5 TIMES         PIC S9(9) USAGE IS COMP-5.
          05 LDATA1                        PIC S9(9) USAGE IS COMP-5.
          05 LDATA2 OCCURS 5 TIMES         PIC S9(9) USAGE IS COMP-5.
          05 FDATA1                        USAGE IS COMP-1.
          05 FDATA2 OCCURS 5 TIMES         USAGE IS COMP-1.
          05 DDATA1                        USAGE IS COMP-2.
          05 DDATA2 OCCURS 5 TIMES         USAGE IS COMP-2.

Since the created file must be used through the COPY command in the COBOL source code, locate the file in the directory specified in $COBCPY. If cobolsample.tar is used, the file is located in the $TMAXIDIR/ucblinc directory.

To efficiently manage the view file, it is recommended to save the file in a separate directory from the directory that contains the COBOL header files provided by Tmax.

Set "export COBCPY=$TMAXDIR/cobinc:$TMAXDIR/ucblinc" and save user-created view files in $TMAXDIR/ucblinc.

The following files are saved in $TMAXDIR/ucblinc.

$ ls -l
-rw-r--r-- 1 tmax dba  671 May  7 18:17 VIEWDEMO.cbl
-rwxr-xr-- 1 tmax dba  381 Apr 30 15:10 fdldemo.f*
-rw-r--r-- 1 tmax dba  755 May  6 23:59 fdldemo_fdl.h
-rw-r--r-- 1 tmax dba 3852 May  6 23:59 tmax.fdl
-rw-r--r-- 1 tmax dba  976 May  7 20:13 tmax.sdl
-rw-r--r-- 1 tmax dba  996 May  7 00:56 viewdemo.sdl
-rw-r-xr-- 1 tmax dba  385 May  7 18:17 viewdemo.v*
-rw-r--r-- 1 tmax dba  574 May  7 20:13 viewdemo_sdl.h
-rw-r--r-- 1 tmax dba  571 Apr 30 14:53 viewdemo_sdl.h

2.4. Example Program

The following is an example of a service program that uses field buffers.

<$TMAXDIR/sample/cobserver/fdlins.pco>

        ******************************************************
        * Service that uses an FDL buffer
        ******************************************************
         IDENTIFICATION        DIVISION.
            PROGRAM-ID.            FDLINS.
            AUTHOR.                TMAX DEVELOPMENT.
         ENVIRONMENT            DIVISION.
            CONFIGURATION         SECTION.

         DATA                     DIVISION.
            FILE                     SECTION.

         WORKING-STORAGE        SECTION.

        ******************************************************
        * Definitions for Tmax ATMI functions
        ******************************************************
         01 TPSVCRET-REC.
         COPY TPSVCRET.
        *
        01 TPTYPE-REC.
        COPY TPTYPE.
      *
        01 TPSTATUS-REC.
        COPY TPSTATUS.
      *
        01 TPSVCDEF-REC.
        COPY TPSVCDEF.
      *
        01 FML-REC.
        COPY FMLINFO.

      ******************************************************
      * Log message definitions
      ******************************************************
        01  LOGMSG.
                05  LOGMSG-SVC  PIC X(16).
                05  FILLER      PIC X(3) VALUES " : ".
                05  LOGMSG-TEXT PIC X(50).
        01  LOGMSG-LEN          PIC S9(9)  COMP-5.

      ******************************************************
      * User defined data records
      ******************************************************
        01 RECV-BUFFER.
           03 RECV-ALIGN        pic S9(9) COMP-5.
           03 RECV-DATA         pic x(1000).

        01 SEND-BUFFER.
           03 SEND-ALIGN        pic S9(9) COMP-5.
           03 SEND-DATA         pic x(1000).

        01 VIEWDEMO.
        COPY VIEWDEMO.

        LINKAGE                 SECTION.
      *
        PROCEDURE               DIVISION.
      *
        000-MAIN.

           PERFORM 100-SVCSTART      THRU 100-EXIT.
           PERFORM 200-FDL2VIEW      THRU 200-EXIT.
           PERFORM 300-VIEW2FDL      THRU 300-EXIT.
           PERFORM 900-TPRETURNSCS   THRU 900-TPRETURNSCS-X.

        000-EXIT.

      ******************************************************
      * Receiving data from a client
      ******************************************************
       100-SVCSTART.
           MOVE LENGTH OF RECV-BUFFER TO LEN.
           CALL "TPSVCSTART" USING TPSVCDEF-REC
                                TPTYPE-REC
                                RECV-BUFFER
                                TPSTATUS-REC.

           IF NOT TPOK
                MOVE "TPSVCSTART Fail" TO LOGMSG-TEXT
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

           IF TPTRUNCATE
                MOVE "Received data was truncated" TO LOGMSG-TEXT
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

           DISPLAY "------------------------------------------------".

           MOVE SERVICE-NAME TO LOGMSG-SVC.
           MOVE "Starting the service " TO LOGMSG-TEXT.
           PERFORM 800-USERLOG.
        100-EXIT.


      ******************************************************
      * Moving FIELD buffer data to a struct
      ******************************************************
        200-FDL2VIEW.
      * VIEWNAME and FML-LENGTH must be specified.
           MOVE "viewdemo" TO VIEWNAME.
           MOVE LEN TO FML-LENGTH.

      * Moving field buffer data to a COBOL structure
           CALL "FVFTOS" USING RECV-BUFFER VIEWDEMO FML-REC.
           IF NOT FOK
                MOVE "FVFTOS FAILED " TO LOGMSG-TEXT
                DISPLAY "FML-STATUS : " FML-STATUS
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

        200-EXIT.

      ******************************************************
      * Moving structure data to a field buffer
      ******************************************************
        300-VIEW2FDL.
      * FML-LENGTH must be used.
           MOVE LENGTH OF SEND-BUFFER  TO FML-LENGTH.
           CALL "FINIT" USING SEND-BUFFER FML-REC.
            IF NOT FOK
                MOVE "FINIT FAILED " TO LOGMSG-TEXT
                DISPLAY "FML-STATUS : " FML-STATUS
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

           MOVE "TEST STRING"  TO SDATA1.
           MOVE "TEST STRING1" TO SDATA2(1).
           MOVE "TEST STRING2" TO SDATA2(2).
           MOVE "TEST STRING3" TO SDATA2(3).

           compute idata1 = idata1 + 10.
           compute idata2(1) = idata2(1) + 10.
           compute idata2(2) = idata2(2) + 10.
           compute idata2(3) = idata2(3) + 10.
           compute idata2(4) = idata2(4) + 10.

           compute ldata1 = ldata1 + 10.
           compute ldata2(1) = ldata2(1) + 10.
           compute ldata2(2) = ldata2(2) + 10.
           compute ldata2(3) = ldata2(3) + 10.
           compute ldata2(4) = ldata2(4) + 10.

           compute fdata1 = fdata1 + 10.
           compute fdata2(1) = fdata2(1) + 10.
           compute fdata2(2) = fdata2(2) + 10.
           compute fdata2(3) = fdata2(3) + 10.
           compute fdata2(4) = fdata2(4) + 10.

           compute ddata1 = ddata1 + 10.
           compute ddata2(1) = ddata2(1) + 10.
           compute ddata2(2) = ddata2(2) + 10.
           compute ddata2(3) = ddata2(3) + 10.
           compute ddata2(4) = ddata2(4) + 10.

      *  Move COBOL structure data to a FDL buffer

           MOVE "viewdemo" TO VIEWNAME.
           SET FUPDATE    TO TRUE.

           CALL "FVSTOF" USING SEND-BUFFER VIEWDEMO FML-REC.
           IF NOT FOK
                MOVE "FVSTOF FAILED " TO LOGMSG-TEXT
                DISPLAY "FML-STATUS : " FML-STATUS
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.
        300-EXIT.

      ******************************************************
      * Writing out a log error message
      ******************************************************
        800-USERLOG.
           DISPLAY LOGMSG.

      ******************************************************
      * The service completed successfully.
      ******************************************************
        900-TPRETURNSCS.
           MOVE "The service executed successfully." TO LOGMSG-TEXT.
           PERFORM 800-USERLOG.
           SET TPSUCCESS TO TRUE.
           MOVE LENGTH OF SEND-BUFFER TO LEN.
           COPY TPRETURN REPLACING
                         DATA-REC BY SEND-BUFFER.
        900-TPRETURNSCS-X.

      ******************************************************
      * The service terminated abnormally.
      ******************************************************
       900-TPRETURNFAIL.
           MOVE "The service terminated abnormally." TO LOGMSG-TEXT.
           PERFORM 800-USERLOG.

           SET TPFAIL TO TRUE.
           MOVE "Cannot process " TO SDATA1.
           MOVE LENGTH OF SEND-BUFFER TO LEN.
           COPY TPRETURN REPLACING
                         DATA-REC BY SEND-BUFFER.
       900-TPRETURNFAIL-X.

The following describes each step in detail.

  1. Declare a field.

    RECV-BUFFER/SEND-BUFFER is a buffer used to send or receive data from a service caller. VIEWDEMO is a structure used to convert a field buffer into a view and vice versa.

      01 FML-REC.
      COPY FMLINFO.
    
    ******************************************************
    * User defined data records
    ******************************************************
      01 RECV-BUFFER.
         03 RECV-ALIGN        pic S9(9) COMP-5.
         03 RECV-DATA         pic x(1000).
    
      01 SEND-BUFFER.
         03 SEND-ALIGN        pic S9(9) COMP-5.
         03 SEND-DATA         pic x(1000).
    
      01 VIEWDEMO.
      COPY VIEWDEMO.
    
    *       VIEWFILE: "viewdemo.v"
    *       VIEWNAME: "viewdemo"
    *
    *     05 SDATA1                    PIC X(20).
    *     05 SDATA2 OCCURS 5 TIMES     PIC X(20)
    *     05 IDATA1                    PIC S9(9) USAGE IS COMP-5.
    *     05 IDATA2 OCCURS 10 TIMES    PIC S9(9) USAGE IS COMP-5.
    *     05 LDATA1                    PIC S9(9) USAGE IS COMP-5.
    *     05 LDATA2 OCCURS 5 TIMES     PIC S9(9) USAGE IS COMP-5.
    *     05 FDATA1                    USAGE IS COMP-1.
    *     05 FDATA2 OCCURS 10 TIMES    USAGE IS COMP-1.
    *     05 DDATA1                    USAGE IS COMP-2.
    *     05 DDATA2 OCCURS 10 TIMES    USAGE IS COMP-2.
  2. Receive a field buffer from a client.

    To receive data from a service caller, TPSVCSTART must be executed first when the service starts.

    ******************************************************
    * Receiving data from a client
    ******************************************************
     100-SVCSTART.
         MOVE LENGTH OF RECV-BUFFER TO LEN.
         CALL "TPSVCSTART" USING TPSVCDEF-REC
                              TPTYPE-REC
                              RECV-BUFFER
                              TPSTATUS-REC.
    
         IF NOT TPOK
              MOVE "TPSVCSTART Fail" TO LOGMSG-TEXT
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
    
         IF TPTRUNCATE
              MOVE "Received data was truncated" TO LOGMSG-TEXT
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
    
         DISPLAY "------------------------------------------------".
    
         MOVE SERVICE-NAME TO LOGMSG-SVC.
         MOVE "Starting a service " TO LOGMSG-TEXT.
         PERFORM 800-USERLOG.
      100-EXIT.
  3. Convert the field buffer to a structure.

    Field buffer data from the service caller is saved in a COBOL structure converted from the buffer. When an array is used, if the data is smaller than the array size, the unfilled portions of the array is filled in with the default value defined in the view file.

    ******************************************************
    * Moving field buffer data to a structure
    ******************************************************
            200-FDL2VIEW.
    * VIEWNAME and FML-LENGTH must be specified.
         MOVE "viewdemo" TO VIEWNAME.
         MOVE LEN TO FML-LENGTH.
    
    * Moving field buffer data to a COBOL structure
         CALL "FVFTOS" USING RECV-BUFFER VIEWDEMO FML-REC.
         IF NOT FOK
              MOVE "FVFTOS FAILED " TO LOGMSG-TEXT
              DISPLAY "FML-STATUS : " FML-STATUS
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
    
      200-EXIT.
  4. Handle data to perform business logic in the COBOL source code.

         MOVE "TEST STRING"  TO SDATA1.
         MOVE "TEST STRING1" TO SDATA2(1).
         MOVE "TEST STRING2" TO SDATA2(2).
         MOVE "TEST STRING3" TO SDATA2(3).
         ……
         compute ddata1 = ddata1 + 10.
         compute ddata2(1) = ddata2(1) + 10.
         compute ddata2(2) = ddata2(2) + 10.
         compute ddata2(3) = ddata2(3) + 10.
         compute ddata2(4) = ddata2(4) + 10.
  5. Create a field buffer used to send data.

    For the field buffer, the received buffer as well as a newly created buffer can be used. To create a new buffer, use FINIT.

    ******************************************************
    * Moving structure data to a field buffer
    ******************************************************
      300-VIEW2FDL.
    * FML-LENGTH must be used.
         MOVE LENGTH OF SEND-BUFFER  TO FML-LENGTH.
         CALL "FINIT" USING SEND-BUFFER FML-REC.
    IF NOT FOK
              MOVE "FINIT FAILED " TO LOGMSG-TEXT
              DISPLAY "FML-STATUS : " FML-STATUS
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
  6. Convert the structure to a field buffer.

    To send data to a service caller, convert structure data used in COBOL to field type data.

        MOVE "viewdemo" TO VIEWNAME.
               SET FUPDATE    TO TRUE.
    
         CALL "FVSTOF" USING SEND-BUFFER VIEWDEMO FML-REC.
               IF NOT FOK
              MOVE "FVSTOF FAILED " TO LOGMSG-TEXT
              DISPLAY "FML-STATUS : " FML-STATUS
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
            300-EXIT.
  7. Send data to a client.

    If the service executes successfully, TPSUCCESS must be used while executing TPRETURN.

    ******************************************************
    * The service completed successfully.
    ******************************************************
      900-TPRETURNSCS.
         MOVE "The service executed successfully." TO LOGMSG-TEXT.
       PERFORM 800-USERLOG.
    
            SET TPSUCCESS TO TRUE.
         MOVE LENGTH OF SEND-BUFFER TO LEN.
               COPY TPRETURN REPLACING
                 DATA-REC BY SEND-BUFFER.
      900-TPRETURNSCS-X.

    If the service fails to execute, TPFAIL must be used while executing TPRETURN.

    ******************************************************
    * The service terminated abnormally.
    ******************************************************
     900-TPRETURNFAIL.
         MOVE "The service terminated abnormally." TO LOGMSG-TEXT.
         PERFORM 800-USERLOG.
    
         SET TPFAIL TO TRUE.
         MOVE "Cannot process " TO SDATA1.
         MOVE LENGTH OF SEND-BUFFER TO LEN.
         COPY TPRETURN REPLACING
                       DATA-REC BY SEND-BUFFER.
     900-TPRETURNFAIL-X.

2.5. Testing a Service Call

Call a service using the tmd utility without writing a client program.

$ cd TMAXDIR/sample/cobclient
$ tmd  -i  tmd_FDLINS

    fkey = 469763049, fname = FDL_S1, type = string, value = TEST STRING
    fkey = 469763050, fname = FDL_S2, type = string, value = TEST STRING1
    fkey = 469763050, fname = FDL_S2, type = string, value = TEST STRING2
    fkey = 469763050, fname = FDL_S2, type = string, value = TEST STRING3
    fkey = 201328593, fname = FDL_I1, type = int, value = 20
    fkey = 201328594, fname = FDL_I2, type = int, value = 30
    fkey = 201328594, fname = FDL_I2, type = int, value = 10
    fkey = 201328594, fname = FDL_I2, type = int, value = 10
    fkey = 201328594, fname = FDL_I2, type = int, value = 10
    fkey = 268438457, fname = FDL_L1, type = long, value = 10010
    fkey = 268438458, fname = FDL_L2, type = long, value = 100010
    fkey = 268438458, fname = FDL_L2, type = long, value = 200010
    fkey = 268438458, fname = FDL_L2, type = long, value = 300010
    fkey = 268438458, fname = FDL_L2, type = long, value = 10
    fkey = 335548321, fname = FDL_F1, type = float, value = 20.123451
    fkey = 335548322, fname = FDL_F2, type = float, value = 30.123449
    fkey = 335548322, fname = FDL_F2, type = float, value = 10.000000
    fkey = 335548322, fname = FDL_F2, type = float, value = 10.000000
    fkey = 335548322, fname = FDL_F2, type = float, value = 10.000000
    fkey = 402658185, fname = FDL_D1, type = double, value = 100010.123450
    fkey = 402658186, fname = FDL_D2, type = double, value = 200010.123450
    fkey = 402658186, fname = FDL_D2, type = double, value = 10.000000
    fkey = 402658186, fname = FDL_D2, type = double, value = 10.000000
    fkey = 402658186, fname = FDL_D2, type = double, value = 10.000000

Since the Tmax configuration file is not read, check TMAX_HOST_PORT, TMAX_HOST_ADDR, and FDLFILE, which are set in the user profile.

3. Global Transaction Program

3.1. Example Program

The following is an example of a service program that uses global transactions.

<$TMAXDIR/sample/cobserver/carraynauto.pco>

      ******************************************************
      * XA service that uses a CARRAY buffer               *
      ******************************************************
        IDENTIFICATION          DIVISION.
        PROGRAM-ID.             CARRAYNAUTO.
        ……
        WORKING-STORAGE         SECTION.
      ******************************************************
      * Definitions for Tmax ATMI functions
      ******************************************************
        01  TPSVCRET-REC.
        COPY TPSVCRET.
      *
        01  TPTYPE-REC.
        COPY TPTYPE.
      *
        01 TPSTATUS-REC.
        COPY TPSTATUS.
      *
        01  TPSVCDEF-REC.
        COPY TPSVCDEF.
      *
        01  TX-RETURN-STATUS.
        COPY TXSTATUS.
      ……
        PROCEDURE               DIVISION.
       000-MAIN.

           PERFORM 100-SVCSTART      THRU 100-EXIT.
           PERFORM 200-DBINSERT      THRU 200-EXIT.
           PERFORM 900-TPRETURNSCS   THRU 900-TPRETURNSCS-X.

       000-EXIT.

        200-DBINSERT.
           MOVE RECV-STRING(1:LEN) TO S-TEMP-ARR.
           MOVE LENGTH OF S-TEMP-ARR TO S-TEMP-LEN.

           CALL "TXBEGIN" USING TX-RETURN-STATUS.
           IF NOT TPOK
                MOVE "FAIL TO TXBEGIN" TO LOGMSG-TEXT
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

      * Handling DB INSERT
           EXEC SQL INSERT INTO TEMP (NAME,SAL)
                     VALUES (RTRIM(:S-TEMP),150)
           END-EXEC.
           IF SQLCODE NOT = 0
                PERFORM 800-SQLERROR
                PERFORM 800-USERLOG
                CALL "TXROLLBACK" USING TX-RETURN-STATUS
                IF NOT TPOK
                        MOVE "txrollback ERROR " TO LOGMSG-TEXT
                        PERFORM 800-USERLOG
                END-IF
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

           CALL "TXCOMMIT" USING TX-RETURN-STATUS.
           IF NOT TPOK
                MOVE "TXCOMMIT ERROR" TO LOGMSG-TEXT
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

           STRING "Inserted data : " S-TEMP-ARR
                  DELIMITED BY SIZE INTO LOGMSG-TEXT.
           PERFORM 800-USERLOG.
           MOVE "Sunccessful " TO SEND-STRING.

       200-EXIT.

The following describes each step in detail.

  1. Start a global transaction.

         CALL "TXBEGIN" USING TX-RETURN-STATUS.
         IF NOT TPOK
              MOVE "FAIL TO TXBEGIN" TO LOGMSG-TEXT
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
  2. Commit a global transaction.

         CALL "TXCOMMIT" USING TX-RETURN-STATUS.
         IF NOT TPOK
              MOVE "TXCOMMIT ERROR" TO LOGMSG-TEXT
              PERFORM 800-USERLOG
              PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
         END-IF.
  3. Cancel a global transaction.

         CALL "TXROLLBACK" USING TX-RETURN-STATUS
         IF NOT TPOK
              MOVE "txrollback ERROR " TO LOGMSG-TEXT
              PERFORM 800-USERLOG
         END-IF.

    For a service that explicitly starts a transaction, "AUTOTRAN=N" (default value) must be set in the Tmax configuration file for Tmax 3.8.9 and later. If "AUTOTRAN=Y" is set, a global transaction automatically starts when a service starts. When the service explicitly uses TXBEGIN, it receives a TPEPROTO error.

Although "AUTOTRAN=N" is set, if both a client and a service explicitly start a transaction, TXBEGIN executed by the service returns the TPEPROTO error.

3.2. Compiling and Starting a Service

Compile a service.

$ sh carray_xa.sh
$ make –f carray_xa.mk

Start a compiled service.

$ tmboot –s carray_xa

3.3. Testing a Service Call

Test a service call.

$ cd $TMAXDIR/sample/cobclient
$ tmd -i t md_CARRAYNAUTO
output: Successful

4. Using TPSVRINIT and TPSVRDONE

4.1. TPSVRINIT

TPSVRINIT initializes a Tmax server. It executes only once when a Tmax server starts. In general, it performs a logic that links servers in a non-xa server group with a database. It is included in cobolsample.tar as tpsvrinit.pco and compiled (.o file is created) and linked with a server program object.

<$TMAXDIR/sample/cobserver/tpsvrinit.pco>

      ******************************************************
      * To link non-XA server with DB (resource manager)
      ******************************************************
        IDENTIFICATION          DIVISION.
        PROGRAM-ID.             TPSVRINIT.
        AUTHOR.                 TMAX DEVELOPMENT.
        ENVIRONMENT             DIVISION.
        CONFIGURATION           SECTION.

        DATA                    DIVISION.
        FILE                    SECTION.

        WORKING-STORAGE         SECTION.

           EXEC SQL BEGIN DECLARE SECTION END-EXEC.
       01  USERNAME          PIC X(10) VARYING.
       01  PASSWD            PIC X(10) VARYING.
           EXEC SQL END DECLARE SECTION END-EXEC.

           EXEC SQL INCLUDE SQLCA END-EXEC.

        LINKAGE                 SECTION.
        01 CMD-LINE.
           05 ARGC PIC 9(4) COMP-5.
           05 ARGV.
              10 ARGS PIC X OCCURS 0 TO 9999 DEPENDING ON ARGC.

        01 SERVER-INIT-STATUS.
        COPY TPSTATUS.
      *
        PROCEDURE       DIVISION USING CMD-LINE SERVER-INIT-STATUS.
      *
       000-TPSVRINIT-START.

      ******************************************************
      * DB error check
      ******************************************************
           EXEC SQL WHENEVER SQLERROR
              DO PERFORM SQL-ERROR
           END-EXEC.

           DISPLAY "ARGC : " ARGC, " ARGV: " ARGV.

      ******************************************************
      * DB connect
      ******************************************************

           MOVE "SCOTT" TO USERNAME-ARR.
           MOVE 5 TO USERNAME-LEN.

           MOVE "TIGER" TO PASSWD-ARR.
           MOVE 5 TO PASSWD-LEN.
           EXEC SQL
               CONNECT :USERNAME IDENTIFIED BY :PASSWD
           END-EXEC.

           DISPLAY "CONNECTED TO ORACLE as User : " USERNAME-ARR.

           SET TPOK IN SERVER-INIT-STATUS TO TRUE.
           EXIT PROGRAM.

       SQL-ERROR.
           EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC.
           DISPLAY " ".
           DISPLAY "ORACLE ERROR DETECTED:".
           DISPLAY SQLERRMC.
           EXEC SQL ROLLBACK WORK RELEASE END-EXEC.

           SET TPEINVAL IN SERVER-INIT-STATUS TO TRUE.
EXIT PROGRAM.

4.2. TPSVRDONE

TPSVRDONE terminates a Tmax server. It executes only once when a Tmax server terminates. In general, it performs a logic that unlinks servers in a non-xa server group with a database. It is included in cobolsample.tar as tpsvrdone.pco and compiled (.o file is created) and linked with a server program object.

<$TMAXDIR/sample/cobserver/tpsvrdone.pco>

      ******************************************************
      * To unlink non-XA server with DB (resource manager)
      ******************************************************
        IDENTIFICATION          DIVISION.
        PROGRAM-ID.             TPSVRDONE.
        AUTHOR.                 TMAX DEVELOPMENT.
        ENVIRONMENT             DIVISION.
        CONFIGURATION           SECTION.
        DATA                    DIVISION.
        FILE                    SECTION.
        WORKING-STORAGE         SECTION.
        01 SERVER-DONE-STATUS.
        COPY TPSTATUS.

             EXEC SQL INCLUDE SQLCA END-EXEC.
      *
        PROCEDURE       DIVISION .
      *
       000-TPSVRDONE-START.

      ******************************************************
      * DB error check
      ******************************************************
           EXEC SQL WHENEVER SQLERROR
              DO PERFORM SQL-ERROR END-EXEC.

      ******************************************************
      * DB disconnect
      ******************************************************
           EXEC SQL COMMIT WORK RELEASE END-EXEC.
           DISPLAY " ".
           DISPLAY "DISCONNECTED TO ORACLE ".

           SET TPOK IN SERVER-DONE-STATUS TO TRUE.
           EXIT PROGRAM.

       SQL-ERROR.
           EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC.
           DISPLAY " ".
           DISPLAY "ORACLE ERROR DETECTED :".
           DISPLAY " ".
           DISPLAY SQLERRMC.
           EXEC SQL ROLLBACK WORK RELEASE END-EXEC.

           SET TPEINVAL IN SERVER-DONE-STATUS TO TRUE.
           EXIT PROGRAM.

4.3. Compiling and Starting a Service

Compile a service.

$ sh carray_nxa.sh
$ make -f carray_nxa.mk

Start the carray_nxa server.

$ tmboot -s carray_nxa

The server status can be checked using the $TMAXDIR/log/ulog/carray_nxa.out userlog file.

ARGC : 00023 ARGV: carray_nxa scott tiger CONNECTED TO ORACLE as User : SCOTT

4.4. Testing a Service Call

Test a service call.

$ cd $TMAXDIR/sample/cobclient
$ tmd -i tmd_CARRAYNXA
output: Successful from from CARRAYNXA

5. Program Calling a Service from a Service

5.1. Example Program

The following is an example of a program that calls a service from a service.

< $TMAXDIR/sample/cobserver/svctpcall.pco >

      ******************************************************
      * Service that uses a CARRAY buffer, not a DB        *
      ******************************************************
        IDENTIFICATION          DIVISION.
        PROGRAM-ID.             SVCTPCALL.
        AUTHOR.                 TMAX DEVELOPMENT.
        ENVIRONMENT             DIVISION.
        CONFIGURATION           SECTION.

        DATA                    DIVISION.
        FILE                    SECTION.

        WORKING-STORAGE         SECTION.
      ******************************************************
      * Definitions for Tmax ATMI functions
      ******************************************************
        01  TPSVCRET-REC.
        COPY TPSVCRET.
      *
        01  TPTYPE-REC.
        COPY TPTYPE.
      *
        01 TPSTATUS-REC.
        COPY TPSTATUS.
      *
        01  TPSVCDEF-REC.
        COPY TPSVCDEF.

      ******************************************************
      * Log message definitions
      ******************************************************
        01  LOGMSG.
                05  LOGMSG-SVC  PIC X(16).
                05  FILLER      PIC X(3) VALUES " : ".
                05  LOGMSG-TEXT PIC X(50).
        01  LOGMSG-LEN          PIC S9(9)  COMP-5.

      ******************************************************
      * User defined data records
      ******************************************************
        01 RECV-STRING          PIC X(100).
        01 SEND-STRING          PIC X(100).

        77 NUM-TPSTATUS         PIC 99.

        PROCEDURE               DIVISION.
      *
000-MAIN.
           PERFORM 100-SVCSTART      THRU 100-EXIT.
           PERFORM 200-TPCALL        THRU 200-EXIT.
           PERFORM 900-TPRETURNSCS   THRU 900-TPRETURNSCS-X.

      ******************************************************
      * Receiving data from a client
      ******************************************************
       100-SVCSTART.
      ……
       100-EXIT.

      **********************************************************
      *  tpcall in service
      **********************************************************
        200-TPCALL.
           MOVE "CARRAYNXA" TO SERVICE-NAME.
           MOVE LENGTH OF SEND-STRING TO LEN IN TPTYPE-REC.

           CALL "TPCALL" USING TPSVCDEF-REC
                               TPTYPE-REC
                               RECV-STRING
                               TPTYPE-REC
                               SEND-STRING
                               TPSTATUS-REC .

           IF NOT TPOK
                MOVE "Service failed" TO LOGMSG-TEXT
                MOVE TP-STATUS TO NUM-TPSTATUS
                STRING "TPCALL call failed : " NUM-TPSTATUS
                      DELIMITED BY SIZE INTO LOGMSG-TEXT
                PERFORM 800-USERLOG
                PERFORM 900-TPRETURNFAIL THRU 900-TPRETURNFAIL-X
           END-IF.

       200-EXIT.

      ******************************************************
      * Writing out a log error message
      ******************************************************
        800-USERLOG.
           DISPLAY LOGMSG.

      ******************************************************
      * The service completed successfully.
      ******************************************************
        900-TPRETURNSCS.
           ……
        900-TPRETURNSCS-X.

      ******************************************************
      * service terminated abnormally.
      ******************************************************
       900-TPRETURNFAIL.
           ……
900-TPRETURNFAIL-X.

A service caller can be a Tmax client or service, which means that a Tmax service can be called from another Tmax service.

To call a service from another service, like the previous example, a buffer used in TPCALL must be used.

     MOVE "CARRAYNXA" TO SERVICE-NAME.
     MOVE LENGTH OF SEND-STRING TO LEN IN TPTYPE-REC.

     CALL "TPCALL" USING TPSVCDEF-REC
                   TPTYPE-REC
                         RECV-STRING
                         TPTYPE-REC
                         SEND-STRING
                  TPSTATUS-REC

5.2. Compiling and Starting a Service

Compile a service.

$ make -f svctpcall.mk

Start a compiled service.

$ tmboot -s svctpcall

5.3. Testing a Service Call

Test a service call.

$ cd $TMAXDIR/sample/cobclient
$ tmd -i tmd_SVCTPCALL
output: Successful from from CARRAYNXA