Examples

This chapter contains examples of the features provided by Tmax.

1. Examples of Communication Mode

This section contains simple examples of synchronous, asynchronous, and interactive applications.

1.1. Synchronous Communication

In the following example, a client copies a string to a STRING buffer and calls a service. A service routine of a server receives the string, changes all characters to upper case, and returns the modified string.

Program Configuration
  • Common program

    Program File Description

    sample.m

    Tmax environment configuration file.

  • Client program

    Program File Description

    sync_cli.c

    Client program.

  • Server program

    Program File Description

    syncsvc.c

    Service program that changes a string to all upper case.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client program

    Feature Description

    Tmax connection

    Basic connection (no client information)

    Buffer type

    STRING

    Communication mode

    Synchronous communication using tpcall()

  • Server program

    Feature Description

    Service

    TOUPPERSTR

    Database connection

    None

Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

*NODE
tmax          TMAXDIR = "/home/tmax",
              APPDIR =  "/home/tmax/appbin",
              PATHDIR = "/home/tmax/path",
              TLOGDIR = "/home/tmax/log/tlog",
              ULOGDIR = "/home/tmax/log/slog",
              SLOGDIR = "/home/tmax/log/ulog"

*SVRGROUP
svg1          NODENAME = tmax

*SERVER
syncsvc       SVGNAME = svg1,
              MIN = 1, MAX = 5,
              CLOPT = " –e $(SVR).err –o $(SVR).out "

*SERVICE
TOUPPERSTR    SVRNAME = syncsvc
Client Program

The following is an example of a client program:

<sync_cli.c>

#include <stdio.h>
#include <string.h>
#include <usrinc/atmi.h>

main(int argc,char *argv[])
{
       char *sendbuf, *recvbuf;
       long rlen;

       if (argc != 2) {
              fprintf(stderr,“Usage: $ %s string \n”,argv[0]);
              exit(1);
       }

       if (tpstart((TPSTART_T*)NULL) == -1) {
              fprintf(stderr,“Tpstart failed\n”);
              exit(1);
       }

       if ((sendbuf = tpalloc(“STRING”,NULL,0)) == NULL) {
              fprintf(stderr,“Error allocation send buffer\n”);
              tpend();
              exit(1);
       }

       if ((recvbuf = tpalloc(“STRING”,NULL,0)) == NULL) {
              fprintf(stderr,“Error allocation recv buffer\n”);
              tpend();
              exit(1);
       }

       strcpy(sendbuf ,argv[ 1 ] ) ;

       if (tpcall(“TOUPPERSTR”,sendbuf,0,&sendbuf,&rlen, TPNOFLAGS) == -1) {
              fprintf(stderr,“Can’t send request to service TOUPPER->%s!\n”,
              tpstrerror(tperrno)) ;
              tpfree(sendbuf) ;
              tpfree(recvbuf) ;
              tpend();
              exit(1);
       }
       printf(“Sent value:%s\n ”,sendbuf );
       printf(“Returned value:%s\n ”,recvbuf );
       tpfree(sendbuf);
       tpfree(recvbuf);
       tpend( );
Server Program

The following is an example of a server program:

<syncsvc.c>

#include <stdio.h>
#include <usrinc/atmi.h>

TOUPPERSTR(TPSVCINFO *msg)
{
       int i;

       for (i = 0; i < msg->len ; i++)
       msg->data[i] = toupper(msg->data[i]);
       msg->data[i] = ‘\0’;

       tpreturn(TPSUCCESS, 0, msg->data, 0, TPNOFLAGS);
}

1.2. Asynchronous Communication

In the following example, a client copies a string to a STRUCT buffer and calls a service. A service routine of a server receives the string, changes it to all upper/lower case, and then returns the modified string. First, the client requests the TOUPPER service through asynchronous communication and then calls the TOLOWER service through synchronous communication. The client receives the results of the TOLOWER service and then receives the results of the TOUPPER service.

Program Configuration
  • Common program

    Program File Description

    demo.s

    Defines a struct buffer.

    sample.m

    Tmax environment configuration file.

  • Client program

    Program File Description

    async_cli.c

    Client program.

  • Server program

    Program File Description

    asyncsvc.c

    Service program that changes a string to all upper/lower case.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    Struct

    Communication mode

    Synchronous and asynchronous

  • Server Program

    Feature Description

    Service

    TOUPPER, TOLOWER

    Database connection

    None

    Communication mode

    Synchronous and asynchronous

Struct Buffer

The following is an example of a struct buffer used for asynchronous communication:

<demo.s>

struct strdata {
   int flag;
   char sdata[20];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

*NODE
tmax          TMAXDIR = "/home/tmax",
              APPDIR = "/home/tmax/appbin",
              PATHDIR = "/home/tmax/path"

*SVRGROUP
svg1          NODENAME = tmax

*SERVER
asyncsvc      SVGNAME = svg1, MIN = 1, MAX = 5

*SERVICE
TOUPPER        SVRNAME = asyncsvc
TOLOWER        SVRNAME = asyncsvc
Client Program

The following is an example of a client program:

<async_cli.c>

#include <stdio.h>
#include <string.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”

main(int argc,char *argv[ ])
{
       struct strdata *sendbuf, *sendbuf1;
       long dlen,clen;
       int cd;

       if (argc != 3) {
              fprintf(stderr, “Usage: $ %s string STRING\n”, argv[0], argv[1]);
              exit(1) ;
       }

       if (tpstart((TPSTART_T *)NULL) == -1) {
              fprintf(stderr, “TPSTART_T failed\n”);
              exit(1) ;
       }

       sendbuf = (struct strdata *)tpalloc(“STRUCT”, “strdata”, 0);
       if ( sendbuf == NULL) {
              fprintf(stderr, “Error allocation send buffer\n”);
              tpend () ;
              exit(1) ;
       }

       sendbuf1 = (struct strdata *)tpalloc(“STRUCT”, “strdata”, 0);
       if (sendbuf1 == NULL) {
              fprintf(stderr, “Error allocation send1 buffer\n”);
              tpend();
              exit(1) ;
       }

       strcpy(sendbuf->sdata, argv[1]);
       strcpy(sendbuf1->sdata, argv[2]);

       if ((cd = tpacall(“TOUPPER”, (char *)sendbuf, 0, TPNOFLAGS)) == -1) {
              fprintf(stderr, “Toupper error -> %s”, tpstrerror(tperrno));
              tpfree((char *)sendbuf);
              tpend();
              exit(1) ;
       }
       if (tpcall(“TOLOWER”,(char *)sendbuf1,0,(char **)&sendbuf1, &dlen,
                               TPSIGRSTRT) == -1) {
              fprintf(stderr, “Tolower error -> %s”, tpstrerror(tperrno));
              tpfree((char *)sendbuf);
              tpend();
              exit(1) ;
       }
       if (tpgetrply(&cd, (char **)&sendbuf, &clen, TPSIGRSTRT) == -1) {
              fprintf(stderr, “Toupper getrply error -> %s”, tpstrerror(tperrno));
              tpfree((char *)sendbuf);
              tpend();
              exit(1) ;
       }
       printf(“Return value %s\n %s\n”, sendbuf -> sdata, sendbuf1 -> sdata);
       tpfree((char *)sendbuf);
       tpfree((char *)sendbuf1);
       tpend() ;
}
Server Program

The following is an example of a server program:

<asyncsvc.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”

TOUPPER(TPSVCINFO *msg)
{
       int i = 0;
       struct strdata *stdata;

       stdata = (struct strdata *)msg -> data;

       while (stdata->sdata[ i ] != ‘\0’) {
       stdata->sdata[ i ] = toupper(stdata->sdata[ i ]);
       i++ ;
       }

       tpreturn(TPSUCCESS, 0, (char *)stdata, 0, TPNOFLAGS);
}

TOLOWER(TPSVCINFO *msg)
{
       int i = 0;
       struct strdata *stdata;

       stdata = (struct strdata *)msg -> data;

       while ( stdata->sdata[ i ] != ‘\0’) {
       stdata->sdata[ i ] = tolower(stdata->sdata[ i ]);
       i++;
       }

       tpreturn(TPSUCCESS, 0, (char *)stdata, 0, TPNOFLAGS);
}

1.3. Interactive Communication

In the following example, a client receives a user’s input and sends a unique number through a STRING buffer. A service routine of a server returns client information from a table saved in a database through a structure. However, only client information that has a number greater than the unique number is returned.

The client sends a unique number with interaction control to the server while setting the interactive mode. The server reads any data that meets the condition in a database and sends it to the client. The client can use TPEVSVCSUCC to check that all data was fetched without error.

Program Configuration
  • Common Program

    Program File Description

    demo.s

    Defines a structure.

    sample.m

    Tmax environment configuration file.

    mktable.sql

    Script for creating a table.

    sel.sql

    Script for outputting tables and data.

  • Client Program

    Program File Description

    conv_cli.c

    Client program.

  • Server Program

    Program File Description

    convsvc.pc

    Server program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRING for transmission and STRUCT for reception

    Communication mode

    Interactive communication STRUCT

  • Server Program

    Feature Description

    Service

    MULTI

    Database connection

    Oracle

Struct Buffer

The following is an example of a structure buffer used for interactive communication:

<demo.s>

struct sel_o {
    char seqno[10];
    char corpno[10];
    char compdate[8];
    int totmon;
    float guarat;
    float guamon;
} ;
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

* DOMAIN
resrc        SHMKEY = 77990, MAXUSER = 256

*NODE
tmax          TMAXDIR = “/home/tmax”,
              APPDIR  = “/home/tmax/appbin”,
              PATHDIR =“/home/tmax/path”

* SVRGROUP
svg1          NODENAME = tmax,
              DBNAME = ORACLE,
              OPENINFO = “ORACLE_XA+Acc=P/scott/tiger+SesTm=60”,
              TMSNAME = svg1_tms

*SERVER
convsvc       SVGNAME = svg1, CONV = Y

*SERVICE
MULTI         SVRNAME = convsvc

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO

Connection information to access an Oracle database.

TMSNAME

Name of the process that handles global transactions.

CONV

Interactive mode server.

Database Script

The following is an example of a script for creating an Oracle table:

<mktable.sql>

sqlplus scott/tiger << EOF
create table multi_sel
(
       seqno      VARCHAR(10),
       corpno     VARCHAR(10),
       compdate   VARCHAR(8),
       totmon     NUMERIC(38),
       guarat      FLOAT,
       guamon     FLOAT
);
create unique index idx_tdb on multi_sel(seqno);
EOF

The following is an example of a script for outputting an Oracle table and data:

<sel.sql>

sqlplus scott/tiger << EOF
Desc multi_sel;
select * from multi_sel;
EOF
Client Program

The following is an example of a client program:

<conv_cli.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

main(int argc, char *argv[])
{
       struct sel_o *rcvbuf;
       char *sndbuf;
       long sndlen, rcvlen, revent;
       int cd;

       if (argc != 2) {
              printf("Usage: client string\n");
              exit(1);
       }

       /* connects to Tmax with tpstart(). */
       if (tpstart((TPSTART_T *) NULL) == -1) {
              printf("tpstart failed\n");
              exit(1);
       }

       if ((sndbuf = tpalloc("STRING", NULL, 12)) == NULL) {
              printf("tpalloc failed:sndbuf\n");
              tpend();
              exit(1);
       }

       if ((rcvbuf = (struct sel_o *)tpalloc("STRUCT", "sel_o", 0)) == NULL) {
              printf("tpalloc failed:rcvbuf\n");
              tpfree(sndbuf);
              tpend();
              exit(1);
       }
       strcpy(sndbuf, argv[1]);

       if ((cd = tpconnect ("MULTI", sndbuf, 0, TPRECVONLY)) == -1){
              printf("tpconnect failed:CONVER service, tperrno=%d\n", tperrno);
              tpfree(sndbuf);
              tpfree((char *)rcvbuf);
              tpend();
              exit(1);
       }

      /* interactive communication connection, The interaction control is sent
         to a server. */
       printf("tpconnect SUCESS \"MULTI\" service\n");
       while ( 1 ) {    /* receives multiple data */
              printf("tprecv strat\n");
              if( tprecv(cd, (char **)&rcvbuf, &rcvlen, TPNOTIME, &revent) < 0 ) {
              /* If ends with tpreturn() in a server */
              if (revent == TPEV_SVCSUCC){
                     printf("all is completed\n");
                     break;
              }
              printf("tprecv failed, tperrno=%s, revent=%x\n",
              tpstrerror(tperrno), revent );
              tpfree(sndbuf);
              tpfree((char *)rcvbuf);
              tpend();
              exit(1);
       }
       printf("seqno = %s\t\t corpno =%s\n", rcvbuf->seqno, rcvbuf->corpno);
       printf("compdate = %s\t\t totmon =%d\n", rcvbuf->compdate, rcvbuf->totmon);
       printf("guarat = %f\t\t guamon =%f\n\n\n", rcvbuf->guarat, rcvbuf->guamon) ;
}
       tpfree(sndbuf);
       tpfree((char *)rcvbuf);
       tpend();
       printf("FINISH\n");
}
Server Program

The following is an example of a server program:

<convsvc.pc>

#include <stdio.h>
#include <string.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”

EXEC SQL begin declare section; /* Oracle global variables declaration */
       char seq[10];
       struct sel_o *sndbuf;
EXEC SQL end declare section;
EXEC SQL include sqlca;

MULTI(TPSVCINFO *msg)
{
       int i, cd;
       long sndlen, revent;

       memset(seq, 0, 10);
       strcpy(seq, msg->data);

       if ((sndbuf = (struct sel_o *) tpalloc (“STRUCT”, “sel_o”, 0)) == NULL) {
               printf(“tpalloc failed:\n”);
               tpreturn (TPFAIL, -1, NULL, 0, TPNOFLAGS);
       }

       /* declares a cursor for large amount of data */
       EXEC SQL declare democursor cursor for
       select *
       from corp
       where seqno > :seq;

       EXEC SQL open democursor;
       EXEC SQL whenever not found goto end_of_fetch;
       if (sqlca.sqlcode != 0){
              printf(“oracle sqlerror=%s”, sqlca.sqlerrm.sqlerrmc);
              tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }

        /* sends data while there is no Oracle error */
       while ( sqlca.sqlcode == 0 ){
              EXEC SQL fetch democursor into :sndbuf;

              if (tpsend (msg->cd, (char *)sndbuf, 0, TPNOTIME, &revent) == -1){
                     printf(“tpsend failed, tperrno=%d, revent=%x\n”, tperrno,
                              revent ) ;
                     tpfree ((char *)sndbuf);
                     tpreturn (TPFAIL, -1, NULL, 0, TPNOFLAGS);
              }
       }

       tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);

       end_of_fetch:
       exec sql close democursor;
       printf(“tpreturn before”);
       tpreturn (TPSUCCESS, 0, NULL, 0, TPNOFLAGS);
}

2. Examples of a Global Transaction Program

A global transaction is when multiple resource managers (databases) and physical entities participate in processing one logical unit. Tmax regards all transactions as global transactions, and 2PC (Two Phase Commit) is used for data integrity.

A client receives a user’s input and sends a unique number and data through a structure buffer. A server updates any data that has the unique number and adds it to a table by calling a service that uses another database. If an error occurs, the client can simultaneously roll back both databases because the client specifies the whole process as a single transaction.

figure 13 1
Access to 2 Databases
Program Configuration
  • Common Program

    Program File Description

    demo.s

    Structure buffer configuration file.

    sample.m

    Tmax environment configuration file.

    mktable.sql

    SQL script for creating a table in a database.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    update.pc

    Server program that executes UPDATE for a database.

    insert.pc

    Server program that executes INSERT for a database.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRUCT

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server program

    Feature Description

    Server program

    2 server programs that use different databases.

    Service

    UPDATE, INSERT

    Database connection

    2 types of Oracle databases

Struct Buffer

The following is an example of a structure buffer used for global transactions:

<demo.s>

struct input {
       int account_id;
       int branch_id;
       char phone[15];
       char address[61];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
res       SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60

*NODE
tmax1     TMAXDIR = "/user/ tmax ",
          APPDIR  = "/user/ tmax /appbin",
          PATHDIR = "/user/ tmax /path",
          TLOGDIR = "/user/ tmax /log/tlog",
          ULOGDIR="/user/ tmax /log/ulog",
          SLOGDIR="/user/ tmax /log/slog"

tmax2     TMAXDIR = "/user/ tmax ",
          APPDIR  = "/user/ tmax /appbin",
          PATHDIR = "/user/ tmax /path",
          TLOGDIR = "/user/ tmax /log/tlog",
          ULOGDIR="/user/ tmax /log/ulog",
          SLOGDIR="/user/ tmax /log/slog"


*SVRGROUP
svg1       NODENAME = tmax1, DBNAME = ORACLE,
           OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
           TMSNAME = svg1_tms

svg2       NODENAME = tmax2, DBNAME = ORACLE,
           OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
           TMSNAME = svg2_tms

*SERVER
update       SVGNAME=svg1
insert       SVGNAME=svg2

*SERVICE
UPDATE       SVRNAME=update
INSERT       SVRNAME=insert
Database Script

The following is an example of a script for creating an Oracle table:

<mktable.sql>

sqlplus scott/tiger << EOF
drop table ACCOUNT;

create table ACCOUNT (
    ACCOUNT_ID  integer,
    BRANCH_ID   integer not null,
    SSN     char(13) not null,
    BALANCE     number,
    ACCT_TYPE   char(1),
    LAST_NAME   char(21),
    FIRST_NAME  char(21),
    MID_INIT    char(1),
    PHONE       char(15),
    ADDRESS     char(61),
    CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID)
);
quit
EOF
Client Program

The following is an example of a client program:

<client.c >

#include <stdio.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

#define TEMP_PHONE "6283-2114"
#define TEMP_ADDRESS "Korea"

int main(int argc, char *argv[])
{
       struct input *sndbuf;
       char *rcvbuf;
       int acnt_id, n, timeout;
       long len;

       if (argc != 2) {
              fprintf(stderr, "Usage:%s account_id \n", argv[0]);
              exit(1);
       }

       acnt_id = atoi(argv[1]);
       timeout = 5;

       n = tmaxreadenv("tmax.env", "tmax");
       if (n < 0) {
              fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno);
              exit(1);
       }

       n = tpstart((TPSTART_T *)NULL);
       if (n < 0) {
              fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno);
              exit(1);
       }
       sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input));
       if (sndbuf == NULL) {
              fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno);
              tpend();
              exit(1);
       }
       rcvbuf = (char *)tpalloc("STRING", NULL, 0);
       if (rcvbuf == NULL) {
              fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno);
              tpend();
              exit(1);
       }
       sndbuf->account_id = acnt_id;
       sndbuf->branch_id = acnt_id;
       strcpy(sndbuf ->phone, TEMP_PHONE);
       strcpy(sndbuf ->address, TEMP_ADDRESS);

       tx_set_transaction_timeout(timeout);
       n = tx_begin();
       if (n < 0)
           fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno);

       n = tpcall("UPDATE", (char *)sndbuf, sizeof(struct input), (char **)&rcvbuf,
                  (long *)&len, TPNOFLAGS);
       if (n < 0) {
           fprintf(stderr, "tpcall fail! tperrno = %d\n", tperrno);
           tpend();
           exit(1);
       }

       n = tx_commit();
       if (n < 0) {
           fprintf(stderr, "tx commit fail! tx error = %d \n", n);
           tx_rollback();
           tpend();
           exit(1);
       }
       printf("rtn msg = %s\n", rcvbuf);
       tpfree((char *)sndbuf);
       tpfree((char *)rcvbuf);
       tpend();
}
Server Program

The following is an example of a server program that executes UPDATE for a database:

<update.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/sdl.h>
#include "../sdl/demo.s"

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;
EXEC SQL BEGIN DECLARE SECTION;
int account_id;
    int     branch_id;
    char    ssn[15];
    char    phone[15];
    char    address[61];
EXEC SQL END DECLARE SECTION;

UPDATE(TPSVCINFO *msg)
{
    struct input *rcvbuf;
    int     ret;
    long    acnt_id, rcvlen;
    char    *send;

    rcvbuf = (struct input *)(msg->data);
    send = (char *)tpalloc("STRING", NULL, 0);
    if (send == NULL) {
       fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno));
       tpreturn(TPFAIL, 0, (char *)NULL, 0, 0);
    }
    account_id = rcvbuf->account_id;
    branch_id = rcvbuf->branch_id;
    strcpy(phone, rcvbuf->phone);
    strcpy(address, rcvbuf->address);
    strcpy(ssn, "1234567");

    EXEC SQL UPDATE ACCOUNT
                SET BRANCH_ID = :branch_id,
                    PHONE = :phone,
                    ADDRESS = :address,
                    SSN = :ssn
              WHERE ACCOUNT_ID = :account_id;
    if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) {
        fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode);
        tpreturn(TPFAIL, -1, (char *)NULL, 0, 0);
    }

    rcvbuf->account_id++;
    ret = tpcall("INSERT", (char *)rcvbuf, 0, (char **)&send, (long *)&rcvlen,
                 TPNOFLAGS);
    if (ret < 0) {
        fprintf(stderr, "tpcall fail tperrno = %d\n", tperrno);
        tpreturn(TPFAIL, -1, (char *)NULL, 0, 0);
    }
    strcpy(send, OKMSG);
    tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

The following is an example of a server program that executes INSERT for a database:

<insert.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/sdl.h>
#include "../sdl/demo.s"

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;
EXEC SQL BEGIN DECLARE SECTION;
    int     account_id;
    int     branch_id;
    char    ssn[15];
    char    phone[15];
    char    address[61];
EXEC SQL END DECLARE SECTION;

INSERT(msg)
TPSVCINFO  *msg;
{
    struct input *rcvbuf;
    int     ret;
    long    acnt_id;
    char    *send;

    rcvbuf = (struct input *)(msg->data);
    send = (char *)tpalloc("STRING", NULL, 0);
    if (send == NULL) {
        fprintf(stderr, "tpalloc fail errno = %s\n", tpstrerror(tperrno));
        tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS);
    }

    account_id = rcvbuf->account_id;
    branch_id = rcvbuf->branch_id;
    strcpy(phone, rcvbuf->phone);
    strcpy(address, rcvbuf->address);
    strcpy(ssn, "1234567");

    /*  Declare && Open Cursor for Fetch */
    EXEC SQL INSERT INTO ACCOUNT (
    ACCOUNT_ID,
    BRANCH_ID,
    SSN,
    PHONE,
    ADDRESS )
    VALUES (
    :account_id, :branch_id, :ssn, :phone, :address);

    if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) {
        printf("insert failed sqlcode = %d\n", sqlca.sqlcode);
        tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS);
    }
    strcpy(send, OKMSG);
    tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

3. Database Program

This section describes several examples that illustrate the use of Oracle and Informix databases.

3.1. Oracle Insert Program

A client receives a user’s input and calls a service through a structure buffer. A server receives the input and adds it to a corresponding table. If an error occurs, a client can roll back the database by specifying the process as a single transaction.

Program Configuration
  • Common Program

    Program File Description

    demo.s

    Structure buffer configuration file.

    sample.m

    Tmax environment configuration file.

    mktable.sql

    SQL script for creating a table in a database.

    sel.sql

    SQL script for outputting the contents of a table in a database.

  • Client Program

    Program File Description

    oins_cli.c

    Client program.

  • Server Program

    Program File Description

    oinssvc.pc

    Oracle source of a service program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRUCT

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    ORAINS

    Database connection

    Oracle database

Struct Buffer

The following is an example of a structure buffer:

<demo.s>

struct ktran {
    int no;
    char name[20];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc             SHMKEY = 77990, MAXUSER = 256

*NODE
tmax              TMAXDIR = /home/tmax,
                  APPDIR = /home/tmax/appbin,
                  PATHDIR = /home/tmax/path

*SVRGROUP
svg1              NODENAME = tmax,
                  DBNAME = ORACLE,
                  OPENINFO = “Oracle_XA+Acc=P/scott/tiger+SesTm=60”,
                  TMSNAME = svg1_tms

*SERVER
oinssvc           SVGNAME = svg1, MIN = 1, MAX = 5

*SERVICE
ORAINS            SVRNAME = oinssvc

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO

Connection information to access an Oracle database. CLOSEINFO does not need to be specified for an Oracle database. It is called by tpsvrinfo().

TMSNAME

Name of the process that handles transactions. Automatic transactions appointed by OPENINFO are handled. The corresponding service included in svg1 is handled in automatic transaction status.

Database Script

The following is an example of a script for creating an Oracle table:

<mktable.sql>

sqlplus scott/tiger << EOF
       create table testdb1 (
       no number(7),
       name char(30)
) ;
EOF

The following is an example of a script for outputting an Oracle table and data:

<sel.sql>

sqlpus scott/tiger << EOF
desc testdb1;
select * from testdb1;
select count (*) from testdb1;
EOF
Client Program

The following is an example of a client program:

<oins_cli.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”

main(int argc, char *argv[])
{
       struct ktran *sndbuf, *rcvbuf;
       long sndlen, rcvlen;
       int cd;

       if (argc != 3) {
       printf(“Usage: client no name\n”);
              exit(1);
       }

       printf(“tpstart-start \n”);
       if(tpstart ((TPSTART_T *) NULL) == -1) {
              printf(“Tpstart failed\n”);
              exit(1);
       }
       printf(“tpstart-ok \n”);

       if((sndbuf=(struct ktran *) tpalloc("STRUCT","ktran",0))==NULL) {
            printf(“tpalloc failed:sndbuf, tperrno=%d\n”, tperrno);
            tpend();
            exit(1) ;
        }

        if((rcvbuf = (struct ktran *) tpalloc("STRUCT", "ktran", 0))== NULL) {
             printf(“tpalloc failed:rcvbuf, tperrno=%d\n”, tperrno);
             tpfree((char *)sndbuf);
             tpend();
             exit(1);
        }

       sndbuf->no = atoi(argv[1]);
       strcpy(sndbuf->name, argv[2]);
       printf(“tpcall-start \n”);
       tx_begin();

       if(tpcall("ORAINS",(char *)sndbuf,0,(char **)&rcvbuf,&rcvlen,TPNOFLAGS)==-1){
            printf(“tpcall failed:ORA service, tperrno=%d”, tperrno);
            printf(“sql code=%d\n”, tpurcode);
            tx_rollback();
            tpfree ((char *)sndbuf);
            tpfree ((char *)rcvbuf);
            tpend();
            exit(1);
       }

       printf(“tpcall-success \n”);
       tx_commit();

       tpfree ((char *)sndbuf);
       tpfree ((char *)rcvbuf);
       tpend();
}
Server Program

The following is an example of a server program:

<oinssvc.pc>

#include <stdio.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”

EXEC SQL begin declare section;
char name[20];
int no;

EXEC SQL end declare section;
EXEC SQL include sqlca;

ORAINS(TPSVCINFO *msg)
{
       struct ktran *stdata;
        stdata = (struct ktran *)msg->data;
        strcpy(name, stdata->name);
        no = stdata->no;
        printf(“Ora service started\n”);

       /* inserts into a database */
       EXEC SQL insert into testdb1(no, name) values(:no, :name);

       if (sqlca.sqlcode != 0){
             printf(“oracle sqlerror=%s”,sqlca.sqlerrm.sqlerrmc);
             tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
        }

       tpreturn (TPSUCCESS, sqlca.sqlcode, stdata, 0, TPNOFLAGS);
}

3.2. Oracle Select Program

A client receives a user’s input and calls a service through a structure buffer. A server receives all corresponding data and returns it using a structure array. If an error occurs, a client can roll back the database by specifying the process as a single transaction.

Program Configuration
  • Common Program

    Program File Description

    demo.s

    Structure buffer configuration file.

    sample.m

    Tmax environment configuration file.

    mktable.sql

    SQL script for creating a table in a database.

    sel.sql

    SQL script for outputting the contents of a table in a database.

  • Client Program

    Program File Description

    oins_cli.c

    Client program.

    cdata.c

    Function module used by a client.

  • Server Program

    Program File Description

    oselsvc.pc

    Oracle source of a service program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Service

    ORASEL

    Buffer type

    STRUCT

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    ORASEL

    Database connection

    Oracle

    Buffer usage

    Buffer size can be changed if necessary.

Struct Buffer

The following is an example of a structure buffer:

<demo.s>

struct stru_his{
       long    ACCOUNT_ID ;
       long    TELLER_ID ;
       long    BRANCH_ID ;
       long    AMOUNT ;
} ;
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc             SHMKEY = 77990, MAXUSER = 256

*NODE
tmax              TMAXDIR =“/home/tmax”,
                  APPDIR =“/home/tmax/appbin”,
                  PATHDIR =“/home/tmax/path”

*SVRGROUP
svg1              NODENAME = tmax,
                  DBNAME = ORACLE,
                  OPENINFO = “Oracle_XA+Acc=P/scott/tiger+SesTm=600”,
                  TMSNAME = svg1_tms

*SERVER
oselsvc           SVGNAME = svg1, MIN = 1, MAX = 5

*SERVICE
ORASEL            SVRNAME = oselsvc

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO

Connection information to access an Oracle database. CLOSEINFO does not need to be specified for an Oracle database.

The following options can be used for OPENINFO:

  • LogDir : Can record an XA-related log in a specified location. If unspecified, the <xa_NULLdate.trc> file is created in $ORACLE_HOME/rdbms/log or the current directory.

  • DbgFl : Determines the level of the debug flag. Options are 0x01 the basic level, 0x04 the OCI level, etc.

TMSNAME

Name of the process that handles transactions.

AUTOTRAN

Corresponding service is automatically processed in transaction status.

The following illustrates the use of LogDir and DbgFl options for OPENINFO:

OPENINFO=“Oracle_XA+Acc=P/account/password +SesTm=60+LogDir=/tmp+DbgFl=0x01”

To prevent a disk from becoming full, disable the Debug mode during development.

Database Script

The following is an example of a script for creating an Oracle table:

<mktable.sql>

sqlplus scott/tiger << EOF
       create table sel_his(
       account_id number(6),
       teller_id number(6),
       branch_id number(6),
       amount number(6)
);
create unique index idx_tdb1 on sel_his(account_id);
EOF

The following is an example of a script for outputting an Oracle table and data:

<sel.sql>

sqlplus scott/tiger << EOF
desc sel_his;
select * from sel_his;
EOF
Client Program

The following is an example of a client program:

<oins_cli.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/tx.h>
#include “../sdl/demo.s”
#define NARRAY 10
#define NOTFOUND 1403

main(int argc,char *argv[])
{
       struct stru_his *transf;
       int i, j;
       long urcode, nrecv, narray = NARRAY;
       long account_id, teller_id, branch_id, amount;

       if (argc != 2) {
              fprintf(stderr,“Usage:$%s ACOUNT_ID !\n”, argv[0]);
              exit(0);
       }

       if (tpstart((TPSTART_T *) NULL) == -1) {    /* connects to Tmax */
           fprintf(stderr,“TPSTART_T(tpinfo) failed -> %s!\n”,
           tpstrerror(tperrno)) ;
           exit(1) ;
       }

       /* creates a c structure buffer */
       transf = (struct stru_his *) tpalloc(“STRUCT”, “stru_his”,0);
       if (transf == (struct stru_his *)NULL) {
              fprintf(stderr,“Tpalloc failed->%s!\n”,
              tpstrerror(tperrno)) ;
              tpend();
              exit(1);
       }
       memset(transf, 0x00, sizeof(struct stru_his));

       account_id = atoi(argv[1]);
       transf->ACCOUNT_ID = account_id;

       /* sets transaction timeout */
       tx_set_transaction_timeout(30);

       /* starts global transactions */
       if (tx_begin() < 0) {
              fprintf(stderr, “tx_begin() failed ->%s!\n”,
              tpstrerror(tperrno));
              tpfree((char*)transf);
              tpend();
              exit(0) ;
       }

       if (tpcall(“ORASEL”,(char *)transf, 0, (char **)&transf, &nrecv,
                  TPNOFLAGS)== -1){
              /* request the“ORASEL” service with synchronous communication */
              fprintf(stderr,“Tpcall(SELECT...)error->%s ! ”,
              tpstrerror(tperrno)) ;
              tpfree((char *)transf);
              /* cancels a transaction if failed */
              tx_rollback();
              tpend();
              exit(0) ;
       }
       /* commits a transaction if successful */
       if (tx_commit() == -1) {
              fprintf(stderr, “tx_commit() failed ->%s!\n”,
              tpstrerror(tperrno)) ;
              tpfree((char *)transf);
                     tpend();
                     exit(0) ;
       }
        /* Received data is an array of a struct. */
       for (j =0 ; j < tpurcode ; j++) {
              /* prints data selected by Oracle */
              if (j == 0)
                     printf(“%-12s%-10s%-10s%-10s\n”,
                    “ACCOUNT_ID”,“TELLER_ID”, “BRANCH_ID”, “AMOUNT”);
              account_id=transf[j].ACCOUNT_ID;
              teller_id=transf[j].TELLER_ID;
              branch_id=(*(transf+j)).BRANCH_ID;
              amount=transf[j].AMOUNT;
       printf(“%-12d %-10d %-10d %-10d\n”, account_id, teller_id,branch_id, amount);
       }
       /* if there is no selected data or it is the end */
       if (urcode == NOTFOUND) {
       printf(“No records selected!\n”);
              tpfree((char *)transf);
              tpend();
              return 0;
}
       tpfree((char *)transf);
       tpend();
}
Server Program

The following is an example of a server program:

<oselsvc.pc>

#include <stdio.h>
#include <usrinc/atmi.h>
#include “../sdl/demo.s”
#define NARRAY 10
#define TOOMANY 2112
#define NOTFOUND 1403
EXEC SQL include sqlca.h;

EXEC SQL begin declare section;
       long key, rowno= NARRAY;
       long account_id[NARRAY],teller_id[NARRAY], branch_id[NARRAY],
       amount[NARRAY] ;
EXEC SQL end declare section;

ORASEL(TPSVCINFO *msg)
{
       struct stru_his *transf;
       int i , lastno;
       transf=(struct stru_his *) msg->data;

       /* transfers contents of the msg buffer to a program variable */
       key = transf->ACCOUNT_ID;

        /* adjusts the size of the transf buffer */
       if((transf=(struct stru_his *) tprealloc((char*)transf,
           sizeof(struct stru_his) * NARRAY ))==(struct stru_his*)NULL){
              fprintf(stderr, “tprealloc error ->%s\n”,
              tpstrerror(tperrno));
              tpreturn(TPFAIL, tperrno, NULL, 0, TPNOFLAGS);
       }

       EXEC SQL select account_id, teller_id, branch_id, amount
                  into :account_id, :teller_id, :branch_id, :amount  from sel_his
                 where account_id > :key
              /* puts data that has account_id greater than the key value sent */
              order by account_id;       /* by a client to a global variable */

       /* sql error check (excludes non-selected or too many data) */
       if (sqlca.sqlcode!=0 && sqlca.sqlcode!=NOTFOUND && sqlca.sqlcode!=TOOMANY) {
              fprintf(stderr,“SQL ERROR ->NO(%d):%s\n”, sqlca.sqlcode,
              sqlca.sqlerrm.sqlerrmc) ;
              tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }

       /* puts the number of access to lastno */
       lastno = sqlca.sqlerrd[2];

       /* too many selected data */
       if (sqlca.sqlcode == TOOMANY)
              lastno =rowno;

       /* No records */
       if (lastno == 0)
              transf->ACCOUNT_ID = 0;

        /* puts data selected by Oracle to a buffer to be sent */
        for ( i = 0 ; i < lastno; i++) {
              transf[i].ACCOUNT_ID = account_id[i];
              transf[i].TELLER_ID = teller_id[i];
              transf[i].BRANCH_ID = branch_id[i];
              transf[i].AMOUNT = amount[i];
       }
       tpreturn(TPSUCCESS, lastno, transf, i * sizeof(struct stru_his),
       TPNOFLAGS );
}

3.3. Informix Insert Program

A client receives a user’s input and calls a service through a structure buffer. A server receives the input and adds it to a corresponding table. A client can roll back by specifying the process as a single transaction when an error occurs.

Check the following before compiling an Informix application.

  1. Check the UNIX environment (.profile,.login, .cshrc).

    Set the following values:

    INFORMIXDIR=/home/informix
    INFORMIXSERVER=tmax
    ONCONFIG=onconfig
    PATH=$INFORMIXDIR/bin: …
    LD_LIBRARY_PATH=/home/informix/lib:/home/informix/lib/esql:
    …
  2. Check the Makefile.

    Check the following operations and settings:

    # Server esql makefile
    
    TARGET  = <target filename>
    APOBJS  = $(TARGET).o
    SDLFILE = info.s
    
    LIBS    = -lsvr -linfs
    # For solaris, add –lnsl –lsocket
    
    OBJS    = $(APOBJS) $(SDLOBJ) $(SVCTOBJ)
    SDLOBJ  = ${SDLFILE:.s=_sdl.o}
    SDLC    = ${SDLFILE:.s=_sdl.c}
    SVCTOBJ = $(TARGET)_svctab.o
    
    CFLAGS =-O -I$(INFORMIXDIR)/incl/esql -I$(TMAXDIR)
    # Solaris 32bit, Compaq, Linux: CFLAGS = -O -I$(INFORMIXDIR)/incl/esql
                                             –I$(TMAXDIR)
    # Solaris 64bit: CFLAGS = -xarch=v9 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    # HP 32bit: CFLAGS = -Ae -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    # HP 64bit: CFLAGS = -Ae +DA2.0W +DD64 +DS2.0 -O -I$(INFORMIXDIR)/incl/esql
                         –I$(TMAXDIR)
    # IBM 32bit: CFLAGS = -q32 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    # IBM 64bit: CFLAGS = -q64 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    
    INFLIBD = $(INFORMIXDIR)/lib/esql
    INFLIBDD = $(INFORMIXDIR)/lib
    INFLIBS = -lifsql -lifasf -lifgen -lifos -lifgls -lm -ldl -lcrypt
               $(INFORMIXDIR)/lib/esql/
    checkapi.o -lifglx -lifxa
    
    APPDIR  = $(TMAXDIR)/appbin
    SVCTDIR = $(TMAXDIR)/svct
    TMAXLIBDIR  = $(TMAXDIR)/lib
    
    #
    .SUFFIXES : .ec .s .c .o
    
    .ec.c :
            esql -e $*.ec
    
    #
    # server compile
    #
    all: $(TARGET)
    
    $(TARGET):$(OBJS)
            $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -L$(INFLIBD) -L$(INFLIBDD) -o $(TARGET)
            $(OBJS) $(LIBS) $(INFLIBS)
            mv $(TARGET) $(APPDIR)/.
            rm -f $(OBJS)
    
    $(APOBJS): $(TARGET).ec
            esql -e -I$(TMAXDIR)/usrinc $(TARGET).ec
            $(CC) $(CFLAGS) -c $(TARGET).c
    
    $(SVCTOBJ):
            touch $(SVCTDIR)/$(TARGET)_svctab.c
            $(CC) $(CFLAGS) -c $(SVCTDIR)/$(TARGET)_svctab.c
    
    $(SDLOBJ):
            $(TMAXDIR)/bin/sdlc -i ../sdl/$(SDLFILE)
            $(CC) $(CFLAGS) -c ../sdl/$(SDLC)
    
    #
    clean:
    -rm -f *.o core $(TARGET) $(TARGET).lis

    <TMS Makefile>

    #
    TARGET  = info_tms
    
    INFOLIBDIR = ${INFORMIXDIR}/lib
    INFOELIBDIR = ${INFORMIXDIR}/esql
    INFOLIBD = ${INFORMIXDIR}/lib/esql
    INFOLIBS = -lifsql -lifasf -lifgen -lifos -lifgls -lm -ldl -lcrypt
               /opt/informix/lib/esql/checkapi.o
     -lifglx -lifxa
    # For solaris, add –lnsl –lsocket –laio –lelf in the libraries
    
    CFLAGS =-O -I$(INFORMIXDIR)/incl/esql -I$(TMAXDIR)
    # Solaris 32bit, Compaq, Linux: CFLAGS = -O -I$(INFORMIXDIR)/incl/esql
                                             –I$(TMAXDIR)
    # Solaris 64bit: CFLAGS = -xarch=v9 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    # HP 32bit: CFLAGS = -Ae -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR)
    # HP 64bit: CFLAGS = -Ae +DA2.0W +DD64 +DS2.0 -O -I$(INFORMIXDIR)/incl/esql
                         –I$(TMAXDIR)
    # IBM 32bit: CFLAGS = -q32 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR
    # IBM 64bit: CFLAGS = -q64 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR
    
    TMAXLIBDIR = $(TMAXDIR)/lib
    TMAXLIBS  = -ltms -linfs
    # CC = /opt/SUNWspro/bin/cc : solaris only
    
    
    $(TARGET): $(APOBJ)
            $(CC) $(CFLAGS) -o $(TARGET) -L$(TMAXLIBDIR) -L$(INFOLIBD)
            -L$(INFOLIBDIR) -L
    $(INFOELIBDIR) $(INFOLIBS) $(TMAXLIBS)
            mv $(TARGET) $(TMAXDIR)/appbin
    
    #
    clean:
            -rm -f  *.o core $(TARGET)
Program Configuration
  • Common Program

    Program File Description

    demo.s

    Structure buffer configuration file.

    sample.m

    Tmax environment configuration file.

    mkdb.sql

    SQL script for creating a database. XA mode is supported when a database is created in logging mode.

    mktable.sql

    SQL script for creating a table in a database.

    sel.sql

    SQL script for outputting the contents of a table in a database.

    info.s

    SDLFILE.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    tdbsvr.ec

    Server program.

    Makefile

    Modifies the Makefile provided by Tmax.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection.

    Buffer type

    STRUCT.

    Communication mode

    Synchronous communication using tpcall().

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    INSERT

    Database connection

    Informix

Struct Buffer

The following is an example of a struct buffer.

<demo.s>

struct info {
     char seq[8];
     char data01[128];
     char data02[128];
     char data03[128];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc            SHMKEY = 77990, MAXUSER = 256

*NODE
tmax             TMAXDIR =”/home/tmax”, A
                 APPDIR =”/home/tmax/appbin”,
                 PATHDIR =”/home/tmax/path”

*SVRGROUP
svg1             NODENAME = tmax,
                 DBNAME = INFORMIX,
                 OPENINFO = “stores7”,
                 CLOSEINFO = “”,
                 TMSNAME = info_tms

*SERVER
tdbsvr          SVGNAME = svg1, MIN = 1, MAX = 5

*SERVICE
INSERT         SVRNAME = tdbsvr

The following properties are added:

Property Description

DBNAME

Specifies the name of the database to be used.

OPENINFO, CLOSEINFO

Sets connection and disconnection information for accessing an Informix database. tpsvrinfo() and tpsvrdone() are used to call the information.

TMSNAME

Specifies the name of the process that handles transactions. Automatic transactions that become available due to OPENINFO are handled. The corresponding service included in svg1 is handled in the automatic transaction state.

Database Script

The following is an example of a script that creates an Informix table.

<mktable.sql>

dbaccess << EOF
create database stores7 with buffered log;
grant connect to public;

database stores7;
drop table testdb1;
create table testdb1 (
        seq        VARCHAR(8) ,
        data01     VARCHAR(120) ,
        data02     VARCHAR(120) ,
        data03     VARCHAR(120)
) lock mode row;

create unique index idx_tdb1 on testdb1(seq);
EOF

The following is an example of a script that outputs an Informix table and data.

<sel.sql>

dbaccess << EOF
database stores7;
select * from testdb1;
EOF
Client Program

The following is an example of a client program:

<client.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/tx.h>
#include “info.s”
main(int argc, char **argv)
{
       struct info *transf;
       char data[256];
       long nrecv;

       /* connects to Tmax. */
       if ((tpstart((TPSTART_T *)NULL) == -1) {
            fprintf(stderr, “tpstart(TPINFO...) failed ->%s!\n”,
            tpstrerror(tperrno)) ;
            exit(1) ;
       }

      /* allocates buffer memory to be used in an application program. */
     if ((transf=(struct info *)tpalloc ("STRUCT","info",0))==(struct info *)NULL){
          fprintf(stderr, “tpalloc(struct info, ...) failed ->%s!\n”,
          tpstrerror(tperrno)) ;
          tpend();
          exit(1) ;
       }

       /* fills the data fields to be transferred. */
       strcpy(transf->seq, “000001”);
       strcpy(transf->data01, “Hello”);
       strcpy(transf->data02, “World”);
       strcpy(transf->data03, “1234”);

        /* sets transaction timeout * /
       tx_set_transaction_timeout (30);

       /* informs of the beginning of a transaction */
       if (tx_begin() < 0) {
              fprintf(stderr, “tx_begin() failed ->%s!\n”,
              tpstrerror(tperrno)) ;
              tpfree ((char *)transf);
              tpend( ); exit(0);
       }

       /* calls a service */
     if (tpcall ("INSERT",(char*) transf,0,(char **)&transf,&nrecv,TPNOFLAGS)==-1) {
         fprintf(stderr,"tpcall(struct info, ...)
         failed ->%s!\n",tpstrerror(tperrno)) ;
         tx_rollback ();
         tpfree ((char *)transf),
         tpend();
          exit(0);
       }

      /* Transactions are complete. */
     if (tx_commit () < 0) {
          fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ;
          tpfree ((char *)transf);
          tpend( );
          exit(0);
       }

       tpfree ((char *)transf );
       /* disconnects from Tmax. */
       tpend( ) ;
}
Server Program

The following is an example of a server program:

< tdbsvr.ec>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include “info.s”

EXEC SQL include sqlca.h;

/* service name*/
INSERT(TPSVCINFO *msg)
{
      /* declares a buffer type for the program */
      struct info *INFO;

       /* declares a buffer type for SQL statements */
       EXEC SQL begin declare section;
       varchar seq[8],buf01[128],buf02[128],buf03[128];
       EXEC SQL end declare section;

       /* receives data in a struct format from the message buffer */
       INFO = (struct info *)msg -> data;

       /* copies data received in a struct format to a database buffer */
       strcpy(seq, INFO->seq);
       strcpy(buf01, INFO->data01);
       strcpy(buf02, INFO->data02);
       strcpy(buf03, INFO->data03);

      /* performs an Insert SQL statement */
       EXEC SQL insert into testdb1 (seq,data01,data02,data03)
       values(:seq, :buf01, :buf02, :buf03);

      /* if an error occurs */
       if ( sqlca.sqlcode ! = 0)  {
             /* informs Insert is failed */
              printf(“SQL error => %d !” ,sqlca.sqlcode);
              tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }

       /* when Insert successfully completes */
       tpreturn (TPSUCCESS, 0, NULL, 0, TPNOFLAGS);
}

3.4. Informix Select Program

A client receives a user’s input and calls a service through a structure buffer. A server receives all corresponding data and returns it using a structure array. If an error occurs, a client can roll back the database by specifying the process as a single transaction.

Program Configuration
  • Common Program

    Program File Description

    acct.s

    SDLFILE.

    sample.m

    Tmax environment configuration file.

    mkdb.sql

    SQL script for creating a database.

    mktables.sql

    SQL script for creating a table in a database.

    sel.sql

    SQL script for outputting the contents of a table in a database.

  • Client Program

    Program File Description

    client.c

    Client program.

    cdate.c

    Function module used by client.c.

  • Server Program

    Program File Description

    sel_acct.ec

    Informix source of a service program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRUCT

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    SEL_ACCT

    Database connection

    Informix

    Buffer usage

    Buffer size can be changed if necessary.

Struct Buffer

The following is an example of a struct buffer:

<acct.s>

struct stru_acct {
    int  ACCOUNT_ID;
    char PHONE[20];
    char ADDRESS[80];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

*NODE
tmax          TMAXDIR =”/home/tmax”,
              APPDIR =”/home/tmax/appbin”,
              PATHDIR =”/home/tmax/path”

*SVRGROUP
svg1          NODENAME = tmax,
              DBNAME = INFORMIX,
              OPENINFO = “stores7”,
              CLOSEINFO = “”,
              TMSNAME = info_tms
*SERVER
SEL_ACCT      SVGNAME = svg1, MIN = 1, MAX = 5

*SERVICE
SEL_ACCT      SVRNAME = sel_acct

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO, CLOSEINFO

Connection and disconnection information to access an Informix database. The information is called from tpsvrinit() and tpsvrdone().

TMSNAME

Name of the process that handles transactions. Automatic transactions appointed by OPENINFO are handled. The corresponding service included in svg1 is handled in automatic transaction status.

Database Script

The following is an example of a script for creating an Informix table:

<mkdb.sql>

dbaccess << EOF
create database stores7 with buffered log;
grant connect to public;

database stores7;
drop table ACCOUNT;

create table ACCOUNT (
       account_id INTEGER,
       phone VARCHAR(20),
       address VARCHAR(80)
) lock mode row;

create unique index idx_tdb1 on ACCOUNT(account_id);
EOF

The following is an example of a script for outputting an Informix table and data:

<sel.sql>

dbaccess << EOF
database stores7;
select * from ACCOUNT;
EOF
Client Program

The following is an example of a client program:

<client.c>

#include <stdio.h>
#include <time.h>
#include <usrinc/atmi.h>
#include <usrinc/tx.h>
#include “acct.s”
#define NOTFOUND 1403

void htime(char *, int *);

main(int argc, char *argv[ ])
{
       struct stru_acct *transf;
       float tps;
       int i, j, loop, cnt_data = 0, sec1, sec2;
       long urcode, nrecv, narray;
       char ts[30], te[30], phone[20], address[80];
       int account_id, key;

       if(argc != 2) {
          fprintf(stderr,“Usage:$%sLOOP (NARRAY = 30) !\n”, argv[0]);
          exit(0) ;
       }

       /*repeats the loop as many as times a user wants*/
       loop = atoi(argv[1]);

        /* connects to Tmax */
       if (tpstart((TPSTART_T *)NULL) == -1) {
           fprintf(stderr, “tpstart(tpinfo) failed ->%s!\n”,
           tpstrerror(tperrno));
           exit(1) ;
       }

      /* sec1 = start time */
       htime(ts,&sec1); key=0;

      /* allocates a message buffer */
     for( i = 0; i < loop; i++) {
         if ((transf=(struct stru_acct *)tpalloc("STRUCT","stru_acct",0))==(struct stru_acct *)NULL) {
               fprintf(stderr,“Tpalloc(STRUCT.. )failed->%s!\n” ,
               tpstrerror(tperrno)) ;
                tpend(); exit(1);
          }
         transf -> ACCOUNT_ID = key;

         /* time-out value= 30 */
         tx_set_transaction_timeout(30) ;

         if (tx_begin() < 0) { /* starts transactions */
              fprintf(stderr, “tx_begin() failed ->%s!\n”, tpstrerror(tperrno)) ;
              tpfree((char*)transf);
              tpend();
              exit(0);
       }

       /* calls a select service */
       if (tpcall(“SEL_ACCT”, (char *)transf, 0, (char **)&transf, &nrecv, TPNOFLAGS)== -1) {
           //* service error: the message buffer is freed, the transaction is
                             cancelled, and the connection is terminated */
            fprintf(stderr,“Tpcall(SELECT...)error->%s! ” ,
                      tpstrerror(tperrno)) ;
            tpfree ((char *)transf);
            tx_rollback ( ) ;
            tpend( ) ;
            exit ( 1 ) ;
       }
       urcode = tpurcode;

      /*The service is successfully completed.
         The actual resource is changed as a result of the transaction */
       if (tx_commit() < 0 ) {
              fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ;
              tpfree((char *)transf);
              tpend();
              exit(0);
       }

      /*if data is selected*/
      if ( urcode != NOTFOUND) {
           narray =urcode;
           /* the last record of selected data */
           key=transf[narray-1].ACCOUNT_ID;
          /* outputs results to a user as many as the number of selected data */
          for ( j = 0 ; j < narray ; j++ ) {
               if ( j == 0)
                   printf(“%-10s%-14s%s\n”, “ACCOUNT_ID”, “PHONE”,“ADDRESS”) ;
                   account_id = transf[j].ACCOUNT_ID;
                   strcpy(phone, transf[j].PHONE);
                   strcpy(address, transf[j].ADDRESS);
                   printf(“%-10d %-14s %s\n”, account_id, phone, address);
            }/* for2 end */

           /* increases the number of results */
           cnt_data += j;

           /* message buffer free */
           tpfree ((char *)transf);
            if(urcode == NOTFOUND) {
               printf(“No records selected!\n”);
               break ;
             }
       }/* for1 end */

       /* message buffer free */
       tpfree ((char *)transf);
       /* disconnects from Tmax */
       tpend ();

       /* sec2 = end time */
       htime(te,&sec2);

       /* calculates processing time for each data */
       printf(“TOT.COUNT = %d\n”, cnt_data);
       printf(“Start time = %s\n”, ts);
       printf(“End time = %s\n”, te);
      if ((sec2-sec1) ! = 0)
           tps = (float) cnt_data / (sec2 - sec1);
       else
           tps = cnt_data;
       printf(“Interval = %d secs ==> %10.2f T/S\n”, sec2-sec1,tps);
}

htime(char *cdate, int *sec)
{
       long time(), timef, pt;
        char ct[20], *ap;
        struct tm *localtime(), *tmp;

        pt = time(&timef);
        *sec = pt;
        tmp = localtime(&timef);
        ap = asctime(tmp);

        sscanf(ap, “%*s%*s%*s%s”,ct);
        sprintf( cdate, “%02d. %02d. %02d %s”, tmp->tm_year, ++tmp->tm_mon,
                 tmp->tm_mday,ct);
}
Server Program

The following is an example of a server program:

<sel_acct.pc>

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/tx.h>
#include “acct.s”
#define NFETCH 5
#define NOTFOUND 100

EXEC SQL include sqlca.h;
EXEC SQL begin declare section;
long account_id, key;
varchar phone[20], address[80];
EXEC SQL end declare section;

SEL_ACCT(TPSVCINFO *msg)
{
       int i , j , nfetch;
       int return_code;
       struct stru_acct *ACCT_V;

       /*receives client data. */
       ACCT_V = (struct stru_acct *) msg->data;

       /* moves an accound ID value to be selected to the key */
       key = ACCT_V->ACCOUNT_ID;

       /* reallocates the size of the client buffer*/
       if ((ACCT_V = (struct stru_acct *)tprealloc((char *)ACCT_V,
           sizeof(struct stru_acct)*NFETCH )) == (struct stru_acct *)NULL) {
           fprintf(stderr, “tprealloc error =%s\n”, tpstrerror(tperrno));
           tpreturn (TPFAIL, tperrno, NULL, 0, TPNOFLAGS);
       }

       /*initializes a buffer*/
       ACCT_V->ACCOUNT_ID = 0;
       strcpy(ACCT_V->PHONE,“ ” ) ;
       strcpy(ACCT_V->ADDRESS,“ ” ) ;

       /* extracts phone and address fields from the ACCOUNT table */
       EXEC SQL declare CUR_1 cursor for
                 select account_id,phone,address
                  into :account_id, :pfone, :address
                  from ACCOUNT
               where account_id > :key;/* if an account ID is larger than
                                                              a field key */

       /* cursor open */
       EXEC SQL open CUR_1;
       /* cursor open error */
       if (sqlca.sqlcode ! = 0) {
              printf(“open cursor error !\n”);
              tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }

       nfetch=0 ;
       return_code = NOTFOUND;

       /* cursor open success */
       while (sqlca.sqlcode == 0) {
           /* fetches data from the location a cursor points one at a time */
           EXEC SQL fetch CUR_1;

           /* fetch error */
           if (sqlca.sqlcode ! = 0) {
               if (sqlca.sqlcode == NOTFOUND)
                    break ;
                break ;
            }

           ACCT_V[nfetch].ACCOUNT_ID = account_id;
           strcpy(ACCT_V[nfetch].PHONE, phone );
           strcpy(ACCT_V[nfetch].ADDRESS, address );

            /* increases the number of selected data */
            nfetch++;
            return_code = nfetch

            /* exits from "while"
              if data is selected as many as the number of NFETCH */
           if (nfetch > NFETCH) {
               nfetch = NFETCH;
               return_code = nfetch;
               break ;
            }
       }
       /* cursor close */
       EXEC SQL close CUR_1;

       /* returns the result and its data to a client */
       tpreturn ( TPSUCCESS, return_code, (char *)ACCT_V,
                  sizeof(struct stru_acct)*nfetch, TPNOFLAGS);
}

3.5. DB2 Program

The client receives user input, stores the EMPNO in a string buffer, and calls the server service, which processes the request and adds it to the corresponding table. The client specifies the transaction so that a rollback can be performed in case of an error.

Program Configuration
  • Common Program

    Program File Description

    sample.m

    Tmax configuration file.

    create.ers

    SQL script to create a database table.

  • Client Program

    Program File Description

    clidb2tx.c

    Client program.

  • Server Program

    Program File Description

    svr_db2.sqc

    Oracle source for the service program.

    Makefile

    Makefile to compile TMS and server programs.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRING

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    XASERVICE2

    Database connection

    DB2

Considerations for testing DB2 integration

When integrating with a DB2 database, check the following:

  1. Whether the DB2 client engine is 32bit or 64bit.

  2. Whether the version of the DB2 client is 8.0 or earlier, or 9.0 or later.

  3. Ensure that the XAOPTION settings in the SVRGROUP section of the Tmax configuration file are configured according to the above conditions.

    • For DB2 clients version 8.0 or earlier

      • If the DB2 client engine is 32bit:

        XAOPTION = "DYNAMIC"
      • If the DB2 client engine is 64bit, and the OS is Linux/UNIX-like:

        XAOPTION = "DYNAMIC XASWITCH32"
      • If the DB2 client engine is 64bit and the OS is Windows:

        XAOPTION = "DYNAMIC"
    • For DB2 clients version 9.0 or later

      • not affected by the DB2 client engine (32bit or 64bit) or the operating system (Linux/UNIX or Windows).

        XAOPTION = not set
  4. Specify a proper library according to the above conditions when compiling TMS or server programs.

    • For DB2 clients version 8.0 or earlier

      • If the DB2 client engine is 32bit

        -ldb2s or $(TMAXDIR)/lib/libdb2s.a
      • If the DB2 client engine is 64bit and the OS is Linux/UNIX-like:

        -ldb2_64s or $(TMAXDIR)/lib64/libdb2_64s.a
      • If the DB2 client engine is 64bit and the OS is Windows:

        -ldb2s or $(TMAXDIR)/lib/libdb2s.a
    • For DB2 clients version 9.0 or later

      • not affected by the DB2 client engine (32bit or 64bit) or the operating system (Linux/UNIX or Windows).

         -ldb2s_static or $(TMAXDIR)/lib/libdb2s_static.a
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
tmax1           SHMKEY = 71990, MINCLH = 1, MAXCLH = 3,
                TPORTNO = 7789, BLOCKTIME = 30,
                MAXCPC = 150

*NODE
phk        TMAXDIR = "/home/tmaxha/tmax",
                APPDIR  = "/home/tmaxha/tmax/appbin",
                PATHDIR = "/home/tmaxha/tmax/path",
                TLOGDIR = "/home/tmaxha/tmax/log/tlog",
                ULOGDIR = "/home/tmaxha/tmax/log/ulog",
                SLOGDIR = "/home/tmaxha/tmax/log/slog"

*SVRGROUP
xa_svg_db2      NODENAME = "phk",
                  DBNAME = IBMDB2,
#                 XAOPTION = "DYNAMIC XASWITCH32",
                  XAOPTION = "DYNAMIC",
                  OPENINFO = "db=test,uid=tmaxha,pwd=ha0115",
                  TMSNAME = tms_db2,
                  RESTART=N

*SERVER
svr_db2                  SVGNAME = xa_svg_db2

*SERVICE
XASERVICE2         SVRNAME = svr_db2

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO

Connection information to integrate the DB2 database.

TMSNAME

Name of the process that handles transactions. Automatic transactions appointed by OPENINFO are handled.

Database Script

The following is an example of a script for creating a DB2 table.

# Execute 'db2start'
$ db2start

# Create a database named 'TPTEST'
$ db2 "CREATE DATABASE TPTEST"

# Connect to the TPTEST database
$ db2 "CONNECT TO TPTEST"

# Create an EMP table
$ db2 -vf create.ers -t

<create.ers>
CREATE TABLE EMP (
         EMPNO                  DECIMAL(8) NOT NULL,
         ENAME                  VARCHAR(16),
         JOB                    VARCHAR(16),
         SAL                    DECIMAL(8),
         HIREDATE               DECIMAL(8),
         XID                    CHAR(32)
);

# Check whether the EMP table is successfully created.
$ db2 "LIST TABLES"

The following is an example of a script for outputting a DB2 table and data:

$ db2 "DESCRIBE TABLE EMP"

Column                         Type      Type
name                           schema    name               Length   Scale Nulls
------------------------------ --------- ------------------ -------- ----- ------
EMPNO                          SYSIBM    DECIMAL                   8     0 No
ENAME                          SYSIBM    VARCHAR                  16     0 Yes
JOB                            SYSIBM    VARCHAR                  16     0 Yes
SAL                            SYSIBM    DECIMAL                   8     0 Yes
HIREDATE                       SYSIBM    DECIMAL                   8     0 Yes
XID                            SYSIBM    CHARACTER                32     0 Yes

  6 record(s) selected.
Client Program

The following is an example of a client program:

<clidb2tx.c>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <usrinc/atmi.h>

int main(int argc, char *argv[])
{
         char         *sndbuf, *rcvbuf;
         long         rcvlen;
         int         ret;

         if ( (ret = tmaxreadenv( "tmax.env","TMAX" )) == -1 ){
                  printf( "tmax read env failed.[%s]\n", tpstrerror(tperrno));
                  exit(1);
         }

         if (tpstart((TPSTART_T *)NULL) == -1){
                  printf("tpstart failed.[%s]\n", tpstrerror(tperrno));
                  exit(1);
         }

         if ((sndbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) {
                  printf("sendbuf alloc failed! [%s]\n", tpstrerror(tperrno));
                  tpend();

                  exit(1);
         }

         if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) {
                  printf("recvbuf alloc failed! [%s]\n", tpstrerror(tperrno));
                  tpfree(sndbuf);
                  tpend();

                  exit(1);
         }

         strcpy(sndbuf, argv[1]);

         ret = tx_begin();
         if (ret < 0) {
                  printf("tx_begin is failed.[%s]\n", tpstrerror(tperrno));
                  resource_free(sndbuf, rcvbuf);

                  exit(1);
         } else
                  printf("tx_begin success.\n");

         if (tpcall("XASERVICE2", sndbuf, strlen(sndbuf), &rcvbuf, &rcvlen, 0) == -1){
                  printf("Can't send request to service XASERVICE2.[%s]\n", tpstrerror(tperrno));
                  ret = tx_rollback();
                  if (ret < 0)
                      printf("tx_rollback is failed. [%s]\n", tpstrerror(tperrno));

                  resource_free(&sndbuf, &rcvbuf);
                  exit(1);
         } else
                  printf("XASERVCE2 success.\n");

         ret = tx_commit();
         if (ret < 0) {
               printf("tx_commit is failed. [%s]\n", tpstrerror(tperrno));
               ret = tx_rollback();
               if (ret < 0)
                    printf("tx_rollback is failed. [%s]\n", tpstrerror(tperrno));
         } else
               printf("tx_commit success.\n");
         resource_free(sndbuf, rcvbuf);
         return 0;
}

resource_free(char* sndbuf, char *rcvbuf)
{
         if (rcvbuf != NULL)
             tpfree((char*)rcvbuf);
         if (sndbuf != NULL)
             tpfree((char*)sndbuf);
         tpend();
}
Server Program

The following is an example of a server program:

<svr_db2.sqc>

#include <stdio.h>
#include <usrinc/atmi.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL begin declare section;
         sqlint32 h_empno;
         sqlint32 h_count;
EXEC SQL end declare section;

XASERVICE2(TPSVCINFO *msg)
{
         char         *res_msg;
         int  h_count=0;

          h_empno = atoi(msg->data);
         printf("h_empno = %d \n", h_empno);

         EXEC SQL
                  INSERT into EMP (EMPNO) VALUES (:h_empno);
         if (sqlca.sqlcode != 0) {
              printf("insertion is failed : sqlcode[%d]%d\n", sqlca.sqlcode, sqlca.sqlstate);
              tpreturn(TPFAIL, -1, 0, 0, 0);
         } else
               EXEC SQL SELECT COUNT(*)
               INTO    :h_count
               FROM    emp
               WHERE   empno = :h_empno;
               if (sqlca.sqlcode != 0) {
                   printf("insertion is failed : sqlcode[%d]%d\n", sqlca.sqlcode, sqlca.sqlstate);
                   tpreturn(TPFAIL, -1, 0, 0, 0);
               } else
                    printf("insertion is success. selcnt(%d) \n", h_count);

           tpreturn(TPSUCCESS, 0, 0, 0, 0);
}
Server Makefile

The following is an example of a server makefile.

# Server makefile for DB2
# Linux 64bit

DB2LIBDIR = $(DB2_HOME)/lib
DB2LIBS           = -ldb2

DB         = TEST
DB2USER = tmaxha
DB2PASS = ha0115

TARGET  = $(COMP_TARGET)
APOBJS  = $(TARGET).o
APOBJS2  = utilemb.o
NSDLOBJ = $(TMAXDIR)/lib64/sdl.o

#OBJS    = $(APOBJS) $(APOBJS2) $(SVCTOBJ)
OBJS    = $(APOBJS)  $(SVCTOBJ)
SVCTOBJ = $(TARGET)_svctab.o

#CFLAGS  = -m64 -O -I$(TMAXDIR) -I$(DB2_HOME)/include
CFLAGS  =  -O -I$(TMAXDIR) -I$(DB2_HOME)/include
LDFLAGS =

TMAXAPPDIR  = $(TMAXDIR)/appbin
TMAXSVCTDIR = $(TMAXDIR)/svct
TMAXLIBDIR  = $(TMAXDIR)/lib64

TMAXLIBS    = -lsvr -ldb2s          # dynmic XAOPTION=DYNAMIC (DB2 Client v8.0(below) 32bit  or  DB2 Client 64bit & Windows)
#TMAXLIBS    = -lsvr -ldb2_64s      # dynmic XAOPTION=DYNAMIC (DB2 Client v8.0(below) 64bit & Linux/Unix)
#TMAXLIBS    = -lsvr -ldb2s_static  #static XAOPTION=none (DB2 Client v9.0(above))
#
.SUFFIXES : .c

.c.o:
         $(CC) $(CFLAGS) $(LDFLAGS) -c $<

#
# server compile
#
all: $(TARGET)

$(TARGET): $(OBJS)
         $(CC) $(CFLAGS) $(LDFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(DB2LIBDIR) $(DB2LIBS) $(OBJS) $(TMAXLIBS) $(NSDLOBJ)
         mv $(TARGET) $(TMAXAPPDIR)
         rm -f $(OBJS)

$(APOBJS): $(TARGET).sqc
         db2 connect to $(DB) user $(DB2USER) using $(DB2PASS)
         db2 prep $(TARGET).sqc bindfile
         db2 bind $(TARGET).bnd
         db2 connect reset
         db2 terminate
         $(CC) $(CFLAGS) $(LDFLAGS) -c $(TARGET).c

$(SVCTOBJ):
         cp -f $(TMAXSVCTDIR)/$(TARGET)_svctab.c .
         touch ./$(TARGET)_svctab.c
         $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c

#
clean:
         :-rm -f *.o core $(TMAXAPPDIR)/$(TARGET) $(TARGET).bnd
TMS Makefile

The following is an example of a TMS makefile.

# TMS Makefile for DB2
# Linux 64bit

TARGET  = tms_db2
APOBJ   = dumy.o

APPDIR  = $(TMAXDIR)/appbin
TMAXLIBD= $(TMAXDIR)/lib64
TMAXLIBS    = -lsvr -ldb2s          # dynmic XAOPTION=DYNAMIC (DB2 Client v8.0(below) 32bit  or  DB2 Client 64bit & Windows)
#TMAXLIBS    = -lsvr -ldb2_64s      # dynmic XAOPTION=DYNAMIC (DB2 Client v8.0(below) 64bit & Linux/Unix)
#TMAXLIBS    = -lsvr -ldb2s_static  #static XAOPTION=none (DB2 Client v9.0(above))

DB2PATH = $(DB2_HOME)
DB2LIBDIR= $(DB2PATH)/lib
DB2LIB  = -ldb2

CFLAGS  =
LDFLAGS =
SYSLIBS =

all: $(TARGET)

$(TARGET): $(APOBJ)
         $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) -L$(TMAXLIBD) $(TMAXLIBS) $(APOBJ) -L$(DB2LIBDIR) $(DB2LIB) $(SYSLIBS)
         mv $(TARGET) $(APPDIR)/.

$(APOBJ):
         $(CC) $(CFLAGS) -c dumy.c
#
clean:
         -rm -f *.o core $(APPDIR)/$(TARGET)

3.6. MQ Program

The client receives user input, stores it in a struct buffer, and calls the server service. The server retrieves the corresponding data using struct arrays and returns the result. The client specifies the transaction so that a rollback can be performed in case of an error.

Program Configuration
  • Common Program

    Program File Description

    sample.m

    Tmax configuration file.

    create.ers

    SQL script to create a database table.

  • Client Program

    Program File Description

    cli_put.c / cli_get.c

    Client program.

  • Server Program

    Program File Description

    mq_xa.c

    MQ source for the service program.

    tms_mq.mk / Makefile.mq

    Makefiles to compile TMS and server programs.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Basic connection

    Buffer type

    STRING

    Communication mode

    Synchronous communication using tpcall()

    Transaction handling

    Transaction scope is specified by a client.

  • Server Program

    Feature Description

    Service

    PUTQ1 / GETQ1

    Database connection

    MQ

Considerations for testing DB2 integration

When integrating with a DB2 database, check the following:

  1. Whether the DB2 client engine is 32bit or 64bit.

  2. Whether the version of the DB2 client is 8.0 or earlier, or 9.0 or later.

  3. Ensure that the XAOPTION settings in the SVRGROUP section of the Tmax configuration file are configured according to the above conditions.

    • For DB2 clients version 8.0 or earlier

      • If the DB2 client engine is 32bit:

        XAOPTION = "DYNAMIC"
      • If the DB2 client engine is 64bit, and the OS is Linux/UNIX-like:

        XAOPTION = "DYNAMIC XASWITCH32"
      • If the DB2 client engine is 64bit and the OS is Windows:

        XAOPTION = "DYNAMIC"
    • For DB2 clients version 9.0 or later

      • not affected by the DB2 client engine (32bit or 64bit) or the operating system (Linux/UNIX or Windows).

        XAOPTION = not set
  4. Specify a proper library according to the above conditions when compiling TMS or server programs.

    • For DB2 clients version 8.0 or earlier

      • If the DB2 client engine is 32bit

        -ldb2s or $(TMAXDIR)/lib/libdb2s.a
      • If the DB2 client engine is 64bit and the OS is Linux/UNIX-like:

        -ldb2_64s or $(TMAXDIR)/lib64/libdb2_64s.a
      • If the DB2 client engine is 64bit and the OS is Windows:

        -ldb2s or $(TMAXDIR)/lib/libdb2s.a
    • For DB2 clients version 9.0 or later

      • not affected by the DB2 client engine (32bit or 64bit) or the operating system (Linux/UNIX or Windows).

         -ldb2s_static or $(TMAXDIR)/lib/libdb2s_static.a
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
tmax1         SHMKEY=@SHMEMKY@,
              MINCLH=1,
              MAXCLH=1,
              TPORTNO=@TPORTNO@,
              BLOCKTIME=5,
              TXTIME=10,
              RACPORT=@TRACPORT@,
              MAXCPC = 150
*NODE
@HOSTNAME@      TMAXDIR = "@TMAXDIR@",
                APPDIR  = "@TMAXDIR@/appbin",
                PATHDIR = "@TMAXDIR@/path",
                TLOGDIR = "@TMAXDIR@/log/tlog",
                ULOGDIR = "@TMAXDIR@/log/ulog",
                SLOGDIR = "@TMAXDIR@/log/slog"

*SVRGROUP
svg1        NODENAME = "@HOSTNAME@", DBNAME = MQ,
               OPENINFO = "QMNAME=MQTEST",
               TMSNAME  = tms_mq
*SERVER
mq_xa        SVGNAME = svg1, CLOPT = "-- -m MQTEST -q ORANGE.LOCAL.QUEUE"

*SERVICE
# Common PUT/GET
PUTQ1        SVRNAME = mq_xa
GETQ1        SVRNAME = mq_xa

The following properties are added:

Property Description

DBNAME

Name of the database to be used.

OPENINFO

Connection information to integrate the MQ database.

TMSNAME

Name of the process that handles transactions. Automatic transactions appointed by OPENINFO are handled.

Database Script

The following is an example of executing MQ commands.

  • Create MQ

    qpsx2@mqm:/opt/mqm/samp>crtmqm MQTEST
    There are 90 days left in the trial period for this copy of WebSphere MQ.
    
    WebSphere MQ queue manager created.
    Directory '/var/mqm/qmgrs/MQTEST' created.
    The queue manager is associated with installation 'Installation1'.
    Creating or replacing default objects for queue manager 'MQTEST'.
    
    Default objects statistics : 74 created. 0 replaced. 0 failed.
    Completing setup.
    Setup completed.
  • Check MQ status

    qpsx2@mqm:/opt/mqm/samp> dspmq
    QMNAME(MQTEST)                                            STATUS(Ended immediately)
  • Start MQ

    qpsx2@mqm:/opt/mqm/samp> strmqm  MQTEST
    There are 90 days left in the trial period for this copy of WebSphere MQ.
    WebSphere MQ queue manager 'MQTEST' starting.
    The queue manager is associated with installation 'Installation1'.
    5 log records accessed on queue manager 'MQTEST' during the log replay phase.
    Log replay for queue manager 'MQTEST' complete.
    Transaction manager state recovered for queue manager 'MQTEST'.
    WebSphere MQ queue manager 'MQTEST' started using V7.5.0.2.
    
    qpsx2@mqm:/opt/mqm/samp> dspmq
    QMNAME(MQTEST)                                            STATUS(Running)
  • Terminate MQ

    endmqm -i MQTEST

The following is a sample test provided by WMQ.

psx2@mqm:/opt/mqm/samp/bin>amqsput ORANGE.LOCAL.QUEUE MQTEST
Sample AMQSPUT0 start
target queue is ORANGE.LOCAL.QUEUE
test
Sample AMQSPUT0 end

qpsx2@mqm:/opt/mqm/samp/bin>amqsget ORANGE.LOCAL.QUEUE MQTEST
Sample AMQSGET0 start
message <test>

qpsx2@mqm:/opt/mqm/samp/bin>amqsgbr ORANGE.LOCAL.QUEUE MQTEST
Sample AMQSGBR0 (browse) start
MQTEST
Messages for ORANGE.LOCAL.QUEUE
1 <test>
no more messages
Sample AMQSGBR0 (browse) end
Client Program

The following is an example of a client program:

<cli_put.c>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>
#include <usrinc/ucs.h>
#include <usrinc/fbuf.h>
#include <usrinc/tx.h>
#include "../sdl/demo_sdl.h"
#include "../fdl/demo_fdl.h"

#define SVCNAME1 "PUTQ1"

int carray_db(str sndbuf, char *rcvbuf, int flag, int iud);

char   myname[100];

main(int argc, char *argv[])
{
         int    in_num;
         int    i, ret, empno, loop_cnt, ins_flag;
         str    sndbuf;
         char   *rcvbuf;
         long   rcvlen;
         int    flags;

         if (argc != 4) {
         printf("Usage: %s empno loop_cnt ins_flag \n", argv[0]);
         printf("flag : 1|0 \n");
         exit(1);
         }

         if ((ret = tmaxreadenv("tmax.env","TMAX")) == -1) {
         printf("<%-15s> tmaxreadenv fail [%s]\n", __FILE__, tpstrerror(tperrno));
         exit(1);
         }

         if ( tpstart((TPSTART_T *)NULL) == -1 ){
         printf("<%-15s> tpstart fail [%s]\n", __FILE__, tpstrerror(tperrno));
         exit(1);
         }

         sndbuf=(str)tpalloc("CARRAY", NULL, 4096);
         if(sndbuf==NULL) {
         printf("<%-15s> tpalloc fail [%s]\n", __FILE__, tpstrerror(tperrno));
         tpend();
         exit(1);
         }

         rcvbuf=(char *)tpalloc("STRING", NULL, 4096);
         if(rcvbuf==NULL) {
         printf("<%-15s> tpalloc fail [%s]\n", __FILE__, tpstrerror(tperrno));
         tpend();
         exit(1);
         }

         strcpy(myname, argv[0]);
         empno = atoi(argv[1]);
         loop_cnt = atoi(argv[2]);
         ins_flag = atoi(argv[3]);

         sndbuf->empno = empno;
         sndbuf->sal   = V_SAL;
         strcpy(sndbuf->ename, V_ENAME);
         strcpy(sndbuf->job, V_JOB);
         strcpy(sndbuf->date, V_HIREDATE);

    for (i=1; i<=loop_cnt; i++)
    {
        printf("\n LOOP COUNT = %d \n", i);

         if (ins_flag == 1)
         {
                  flags = INSERT;

                  printf(">> INSERT : ROLLBACK TEST \n");
                  carray_db (sndbuf, rcvbuf, ROLLBACK, flags);

                  printf(">> INSERT : COMMIT TEST \n");
                  carray_db (sndbuf, rcvbuf, COMMIT, flags);
         }
    }
         tpfree((char *)sndbuf);
         tpfree((char *)rcvbuf);
         tpend();
}

int carray_db(str sndbuf, char *rcvbuf, int flag, int iud)
{
         int ret, cd;
         long rlen;

         ret = tx_begin();
        if(ret < 0)
        {
                  printf("<%-15s> tx_begin fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
        }

        if(iud == INSERT)
                strcpy(sndbuf->svcname01, SVCNAME1);
        else
        {
                  printf("[%s] flags must be INSERT or UPDATE or DELETE\n", myname);
                  exit(1);
        }
         cd = tpcall(sndbuf->svcname01, (char *)sndbuf, sizeof(struct temp_str), (char **)&rcvbuf, (long *)&rlen, 0 );
        if(cd < 0)
        {
                  printf("<%-15s> tpcall [%s]\n", __FILE__, tpstrerror(tperrno));
                  tx_rollback();
                  exit(1);
        }

         printf("[%s] [%s]\n", myname, rcvbuf);

         if(flag == COMMIT)
         {
         ret = tx_commit();
                 if(ret < 0)
                {
                  printf("<%-15s> tx_commit fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
                 }
         } else {
         ret = tx_rollback();
                 if(ret < 0)
                {
                  printf("<%-15s> tx_rollback fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
                  }
         }
         return 0;
}

<cli_get.c>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>
#include <usrinc/ucs.h>
#include <usrinc/fbuf.h>
#include <usrinc/tx.h>
#include "../sdl/demo_sdl.h"
#include "../fdl/demo_fdl.h"

#define SVCNAME1 "GETQ1"

int carray_db(str sndbuf, char *rcvbuf, int flag, int iud);
char   myname[100];

main(int argc, char *argv[])
{
         int    in_num;
         int    i, ret, empno, loop_cnt, ins_flag;
         str    sndbuf;
         char   *rcvbuf;
         long   rcvlen;
         int    flags;

         if (argc != 4) {
                  printf("Usage: %s empno loop_cnt ins_flag \n", argv[0]);
         printf("flag : 1|0 \n");
         exit(1);
         }

         if ((ret = tmaxreadenv("tmax.env","TMAX")) == -1) {
         printf("<%-15s> tmaxreadenv fail [%s]\n", __FILE__, tpstrerror(tperrno));
         exit(1);
         }

         if ( tpstart((TPSTART_T *)NULL) == -1 ){
         printf("<%-15s> tpstart fail [%s]\n", __FILE__, tpstrerror(tperrno));
         exit(1);
         }

         sndbuf=(str)tpalloc("CARRAY", NULL, 4096);
         if(sndbuf==NULL) {
         printf("<%-15s> tpalloc fail [%s]\n", __FILE__, tpstrerror(tperrno));
         tpend();
         exit(1);
         }

         rcvbuf=(char *)tpalloc("STRING", NULL, 4096);
         if(rcvbuf==NULL) {
         printf("<%-15s> tpalloc fail [%s]\n", __FILE__, tpstrerror(tperrno));
         tpend();
         exit(1);
         }

         strcpy(myname, argv[0]);
         empno = atoi(argv[1]);
         loop_cnt = atoi(argv[2]);
         ins_flag = atoi(argv[3]);

         sndbuf->empno = empno;
         sndbuf->sal   = V_SAL;
         strcpy(sndbuf->ename, V_ENAME);
         strcpy(sndbuf->job, V_JOB);
         strcpy(sndbuf->date, V_HIREDATE);

    for (i=1; i<=loop_cnt; i++)
    {
        printf("\n LOOP COUNT = %d \n", i);

         if (ins_flag == 1)
         {
                  flags = INSERT;

                  printf(">> INSERT : ROLLBACK TEST \n");
                  carray_db (sndbuf, rcvbuf, ROLLBACK, flags);

                  printf(">> INSERT : COMMIT TEST \n");
                  carray_db (sndbuf, rcvbuf, COMMIT, flags);
         }
    }
         tpfree((char *)sndbuf);
         tpfree((char *)rcvbuf);
         tpend();
}

int carray_db(str sndbuf, char *rcvbuf, int flag, int iud)
{
         int ret, cd;
         long rlen;

         ret = tx_begin();
        if(ret < 0)
        {
                  printf("<%-15s> tx_begin fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
        }

        if(iud == INSERT)
                strcpy(sndbuf->svcname01, SVCNAME1);
        else
        {
                  printf("[%s] flags must be INSERT or UPDATE or DELETE\n", myname);
                  exit(1);
        }
         cd = tpcall(sndbuf->svcname01, (char *)sndbuf, sizeof(struct temp_str), (char **)&rcvbuf, (long *)&rlen, 0 );
        if(cd < 0)
        {
                  printf("<%-15s> tpcall [%s]\n", __FILE__, tpstrerror(tperrno));
                  tx_rollback();
                  exit(1);
        }

         printf("[%s] [%s]\n", myname, rcvbuf);

         if(flag == COMMIT)
         {
         ret = tx_commit();
                 if(ret < 0)
                {
                  printf("<%-15s> tx_commit fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
                 }
         } else {
         ret = tx_rollback();
                 if(ret < 0)
                {
                  printf("<%-15s> tx_rollback fail [%s]\n", __FILE__, tpstrerror(tperrno));
                  exit(1);
                  }
         }

         return 0;
}
Server Program

The following is an example of a server program:

<mq_xa.c>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmqc.h>
#include <getopt.h>
#include <usrinc/atmi.h>
#include <usrinc/tmaxapi.h>
#include <usrinc/fbuf.h>
#include <usrinc/tx.h>
#include "../sdl/demo_sdl.h"
#include "../fdl/demo_fdl.h"

#define MQ_CSP_PASSWORD_LENGTH         256

MQHCONN  Hcon;                   /* connection handle             */
MQHOBJ   Hobj;                   /* object handle                 */
char     QMName[50];             /* queue manager name            */
char     QName[50];              /* queue name                    */
MQOD     od = {MQOD_DEFAULT};    /* Object Descriptor             */
MQLONG   OpenCode = MQCC_FAILED; /* MQOPEN completion code        */
MQLONG   CReason;                /* reason code for MQCONNX       */

int tpsvrinit(int argc, char **argv)
{
         /*   Declare MQI structures needed                                */
         MQCNO   cno = {MQCNO_DEFAULT};   /* connection options            */
         MQCSP   csp = {MQCSP_DEFAULT};   /* security parameters           */
         MQLONG   O_options;              /* MQOPEN options                */
         MQLONG   CompCode;               /* completion code               */
         MQLONG   Reason;                 /* reason code                   */
         char    *UserId = NULL;          /* UserId for authentication     */
         char     Password[MQ_CSP_PASSWORD_LENGTH + 1] = {0}; /* For auth  */
         int                  c;

         strcpy(QMName, "QM1");
         strcpy(QName, "Q1");

         opterr = 0;
         while ((c = getopt(argc, argv, "m:q:u:p:")) != EOF) {
                  switch (c) {
                           case 'm':
                                    strcpy(QMName, optarg);
                                    break;
                           case 'q':
                                    strcpy(QName, optarg);
                                    break;
                           case 'u':
                                    UserId = optarg;
                                    break;
                           case 'p':
                                    strcpy(Password, optarg);
                                    break;
                           case '?':
                           default:
                                    break;
                  }
         }

         if (UserId != NULL) {
                  cno.SecurityParmsPtr = &csp;
                  cno.Version = MQCNO_VERSION_5;

                  csp.AuthenticationType = MQCSP_AUTH_USER_ID_AND_PWD;
                  csp.CSPUserIdPtr = UserId;
                  csp.CSPUserIdLength = strlen(UserId);
                  csp.CSPPasswordPtr = Password;
                  csp.CSPPasswordLength = strlen(csp.CSPPasswordPtr);
         }

         MQCONNX(QMName,                 /* queue manager                  */
                  &cno,                  /* connection options             */
                  &Hcon,                 /* connection handle              */
                  &CompCode,             /* completion code                */
                  &CReason);             /* reason code                    */
         if (CompCode == MQCC_FAILED) {
                  printf("MQCONNX ended with reason code %d\n", CReason);
                  return -1;
         } else if (CompCode == MQCC_WARNING) {
                  printf("MQCONNX generated a warning with reason code %d\n", CReason);
                  printf("Continuing...\n");
         }

         strncpy(od.ObjectName, QName, (size_t)MQ_Q_NAME_LENGTH);
         printf("target queue is %s\n", od.ObjectName);

#if 0
         if (argc > 5)
         {
                  strncpy(od.ObjectQMgrName, argv[5], (size_t) MQ_Q_MGR_NAME_LENGTH);
                  printf("target queue manager is %s\n", od.ObjectQMgrName);
         }

         if (argc > 6)
         {
                  strncpy(od.DynamicQName, argv[6], (size_t) MQ_Q_NAME_LENGTH);
                  printf("dynamic queue name is %s\n", od.DynamicQName);
         }
#endif

         /*   Open the target message queue for output                   */
         O_options = MQOO_OUTPUT            /* open queue for output     */
                  | MQOO_INPUT_AS_Q_DEF     /* open queue for input      */
                  | MQOO_FAIL_IF_QUIESCING  /* but not if MQM stopping   */
                  ;                         /* = 0x2010 = 8208 decimal   */

         MQOPEN(Hcon,                       /* connection handle           */
                  &od,                      /* object descriptor for queue */
                  O_options,                /* open options                */
                  &Hobj,                    /* object handle               */
                  &OpenCode,                /* MQOPEN completion code      */
                  &Reason);                 /* reason code                 */
         if (Reason != MQRC_NONE) {
                  printf("MQOPEN ended with reason code %d\n", Reason);
         }
         if (OpenCode == MQCC_FAILED) {
                  printf("unable to open queue for output\n");
         }
         return 0;
}

int tpsvrdone()
{
         MQLONG   C_options;              /* MQCLOSE options              */
         MQLONG   CompCode;               /* completion code              */
         MQLONG   Reason;                 /* reason code                  */

         /*   Close the target queue (if it was opened)                   */
         if (OpenCode != MQCC_FAILED) {
                  C_options = MQCO_NONE;     /* no close options          */
                  MQCLOSE(Hcon,              /* connection handle         */
                           &Hobj,            /* object handle             */
                           C_options,
                           &CompCode,        /* completion code           */
                           &Reason);         /* reason code               */

                  /* report reason, if any     */
                  if (Reason != MQRC_NONE) {
                           printf("MQCLOSE ended with reason code %d\n", Reason);
                  }
         }

         /*   Disconnect from MQM if not already connected                 */
         if (CReason != MQRC_ALREADY_CONNECTED) {
                  MQDISC(&Hcon,               /* connection handle         */
                           &CompCode,         /* completion code           */
                           &Reason);          /* reason code               */

                  /* report reason, if any     */
                  if (Reason != MQRC_NONE) {
                           printf("MQDISC ended with reason code %d\n", Reason);
                  }
         }
         return 0;
}

PUTQ1(TPSVCINFO *msg)
{
         MQMD     md = {MQMD_DEFAULT};    /* Message Descriptor            */
         MQPMO   pmo = {MQPMO_DEFAULT};   /* put message options           */
         MQLONG   CompCode;               /* completion code               */
         MQLONG   Reason;                 /* reason code                   */

         str  sndbuf;
         char *rcvbuf;
         char tmp[1024];

         sndbuf = (str)msg->data;
         rcvbuf=(char *)tpalloc("STRING", NULL, 4096);
        if(rcvbuf==NULL) {
                printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno));
                  tpreturn(TPFAIL, -1, NULL, 0, 0);
        }

         memcpy(md.Format,           /* character string format            */
                  MQFMT_STRING, (size_t)MQ_FORMAT_LENGTH);

         pmo.Options = MQPMO_SYNCPOINT
                  | MQPMO_FAIL_IF_QUIESCING;
         /* pmo.Options |= MQPMO_NEW_MSG_ID;                           */
         /* pmo.Options |= MQPMO_NEW_CORREL_ID;                        */

         memcpy(md.MsgId, MQMI_NONE, sizeof(md.MsgId) );

         MQPUT(Hcon,                /* connection handle               */
                  Hobj,             /* object handle                   */
                  &md,              /* message descriptor              */
                  &pmo,             /* default options (datagram)      */
                  msg->len,         /* message length                  */
                  sndbuf->job,      /* message buffer                  */
                  &CompCode,        /* completion code                 */
                  &Reason);         /* reason code                     */
         if (Reason != MQRC_NONE) {
                  printf("MQPUT ended with reason code %d\n", Reason);
         }
         if (CompCode != MQCC_FAILED) {
                  sprintf(tmp, "[%s] MQPUT Success", msg->name);
                  strcpy(rcvbuf, tmp);
                  tpreturn(TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0);
         }
         else{
                  sprintf(tmp, "[%s] MQPUT Fail", msg->name);
                  strcpy(rcvbuf, tmp);
                  tpreturn(TPFAIL, 0, tmp, strlen(rcvbuf), 0);
         }
}

GETQ1(TPSVCINFO *msg)
{
         MQMD     md = {MQMD_DEFAULT};    /* Message Descriptor            */
         MQGMO   gmo = {MQGMO_DEFAULT};   /* get message options           */
         MQLONG   messlen;                /* message length                */
         MQLONG   CompCode;               /* completion code               */
         MQLONG   Reason;                 /* reason code                   */
         char *rcvbuf;
         long rcvlen;

         rcvbuf=(char *)tpalloc("STRING", NULL, 4096);
        if(rcvbuf==NULL) {
                printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno));
                  tpreturn(TPFAIL, -1, NULL, 0, 0);
        }

         /*gmo.Version = MQGMO_VERSION_2;*/ /* Avoid need to reset Message */
         /*gmo.MatchOptions = MQMO_NONE; */ /* ID and Correlation ID after */
         /* every MQGET                 */
         gmo.Options = MQGMO_WAIT         /* wait for new messages       */
                  | MQPMO_SYNCPOINT
                  | MQGMO_CONVERT;        /* convert if necessary        */
         gmo.WaitInterval = 15000;        /* 15 second limit for waiting */

         rcvlen = 4096 -1; /* buffer size available for GET   */

         memcpy(md.MsgId, MQMI_NONE, sizeof(md.MsgId));
         memcpy(md.CorrelId, MQCI_NONE, sizeof(md.CorrelId));
         md.Encoding       = MQENC_NATIVE;
         md.CodedCharSetId = MQCCSI_Q_MGR;

         MQGET(Hcon,                  /* connection handle                 */
                  Hobj,               /* object handle                     */
                  &md,                /* message descriptor                */
                  &gmo,               /* get message options               */
                  rcvlen,             /* buffer length                     */
                  rcvbuf,             /* message buffer                    */
                  &messlen,           /* message length                    */
                  &CompCode,          /* completion code                   */
                  &Reason);           /* reason code                       */

         /* report reason, if any     */
         if (Reason != MQRC_NONE) {
                if (Reason == MQRC_NO_MSG_AVAILABLE) {   /* special report for normal end    */
                    printf("no more messages\n");
                } else {                      /* general report for other reasons */
                    printf("MQGET ended with reason code %d\n", Reason);

                     /* treat truncated message as a failure for this sample */
                    if (Reason == MQRC_TRUNCATED_MSG_FAILED) {
                        CompCode = MQCC_FAILED;
                    }
               }
         }

         if (CompCode != MQCC_FAILED)
             tpreturn(TPSUCCESS, 0, rcvbuf, rcvlen, 0);
         else
             tpreturn(TPFAIL, 0, NULL, 0, 0);
}
Server Makefile

The following is an example of a server makefile.

# Server MQ makefile LInux 32bit

TARGET         = $(COMP_TARGET)
APOBJS         = $(TARGET).o
NSDLOBJ = $(TMAXDIR)/lib/sdl.o

#MQLIB = -lmqm           # Server for C
#MQLIB = -lmqm_r         # Server for C for threaded
#MQLIB = -lmqmxa         # Server XA interface
#MQLIB = -lmqmxa_r       # Server XA interface for threaded

#LIBS    = -lsvr -lmqs -lmqmxa -lmqm         # for non-threaded
LIBS    = -lsvr -lmqs -lmqmxa_r -lmqm_r      # for threaded
OBJS    = $(APOBJS) $(SVCTOBJ)
SVCTOBJ = $(TARGET)_svctab.o

#CFLAGS  = -O -I$(TMAXDIR) -I$(HOME)/include -L$(HOME)/lib -I$(MQ_HOME)/inc
CFLAGS  = -m32 -O -I$(TMAXDIR)  -I$(MQ_HOME)/inc

APPDIR  = $(TMAXDIR)/appbin
SVCTDIR = $(TMAXDIR)/svct
TMAXLIBDIR  = $(TMAXDIR)/lib

MQLIBD         = $(MQ_HOME)/lib

#
.SUFFIXES : .c

.c.o:
         $(CC) $(CFLAGS) -c $<

#
# server compile
#
all: $(TARGET)

$(TARGET): $(OBJS)
         $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -L$(MQLIBD) -o $(TARGET) $(OBJS) $(LIBS) $(NSDLOBJ)
         mv $(TARGET) $(APPDIR)/.
         rm -f $(OBJS)

$(SVCTOBJ):
         cp -f $(SVCTDIR)/$(TARGET)_svctab.c .
         touch ./$(TARGET)_svctab.c
         $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c

#
clean:
         -rm -f *.o core $(APPDIR)/$(TARGET) $(TARGET).lis
TMS Makefile

The following is an example of a TMS makefile.

# TMS Makefile for MQ
# Linux 32bit

MQLIBDIR = $(MQ_HOME)/lib
#MQLIB = -lmqmxa         # Server XA interface
MQLIB = -lmqmxa_r        # Server XA interface for threaded

TARGET  = tms_mq
APOBJ   = dumy.o

APPDIR  = $(TMAXDIR)/appbin
TMAXLIBD= $(TMAXDIR)/lib
TMAXLIBS= -ltms -lmqs

CFLAGS  = -m32
LDFLAGS =
SYSLIBS =

all : $(TARGET)

$(TARGET): $(APOBJ)
         $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) -L$(TMAXLIBD) $(TMAXLIBS) $(APOBJ) -L$(MQLIBDIR) $(MQLIB)
         mv $(TARGET) $(APPDIR)/.

$(APOBJ):
         $(CC) $(CFLAGS) -c dumy.c
#
clean:
         -rm -f *.o core $(APPDIR)/$(TARGET)

4. Database Integration Program

This section provides examples of database integration programs that can be used when developing applications. Database integration can be classified into two types: homogeneous and heterogeneous.

4.1. Synchronous mode (homogeneous)

The following figure shows the program flow for connecting to a homogeneous database in synchronous mode.

figure 13 1
Flow of Homogeneous Database Connection (Synchronous Mode)
Program Configuration
  • Common Program

    Program File Description

    demo.s

    SDLFILE.

    sample.m

    Tmax configuration file.

    tmax.env

    Environment file.

    mktable.sql

    SQL script to create a database table.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    update.pc, insert.pc

    Server program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client program

    Feature Description

    Tmax connection

    Connection with NULL parameter

    Buffer type

    STRUCT

    Subtype

    The input struct file needs to be compiled using sdlc to create an SDL file.

    Transaction handling

    Specified by client.

  • Server Program

    Feature Description

    Service count

    The UPDATE service requests for the INSERT service.

    Database connection

    Oracle. The database information must be set in the SVRGROUP section in the Tmax configuration file.

System Requirements
Description

Platform

SunOS 5.7 32bit

Database

Oracle 8.0.5

Struct Buffer

The following is an exmaple of a struct buffer.

<demo.s>

struct input {
        int     account_id;
        int     branch_id;
        char    phone[15];
        char    address[61];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
res   SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60

*NODE
tmax          TMAXDIR = "/user/ tmax ",
              APPDIR  = "/user/ tmax /appbin",
              PATHDIR = "/user/ tmax /path",
              TLOGDIR = "/user/ tmax /log/tlog",
              ULOGDIR="/user/ tmax /log/ulog",
              SLOGDIR="/user/ tmax /log/slog"

*SVRGROUP
svg1          NODENAME = tmax, DBNAME = ORACLE,
              OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60",
              TMSNAME = svg1_tms

*SERVER
update        SVGNAME=svg1
insert        SVGNAME=svg1

*SERVICE
UPDATE        SVRNAME=update
INSERT        SVRNAME=insert

The following is an example of an environment file:

<tmax.env>

[tmax]
TMAX_HOST_ADDR=192.168.1.39
TMAX_HOST_PORT=8880
SDLFILE=/user/tmax/sample/sdl/tmax.sdl
TMAX_CONNECT_TIMEOUT=5
Database Script

The following is an example of an SQL script that creates a database table:

<mktable.sql>

$ORACLE_HOME/bin/sqlplus bmt/bmt <<!
drop table ACCOUNT;
create table ACCOUNT (
        ACCOUNT_ID  integer,
        BRANCH_ID   integer not null,
        SSN     char(13) not null,
        BALANCE     number,
        ACCT_TYPE   char(1),
        LAST_NAME   char(21),
        FIRST_NAME  char(21),
        MID_INIT    char(1),
        PHONE       char(15),
        ADDRESS     char(61),
        CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID)
);
quit
!
Client Program

The following is an example of a client program:

<client.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

#define TEMP_PHONE "6283-2114"
#define TEMP_ADDRESS "Korea"

int main(int argc, char *argv[])
{
        struct input *sndbuf;
        char    *rcvbuf;
        int acnt_id, n, timeout;
        long    len;

        if (argc != 2) {
            fprintf(stderr, "Usage:%s account_id \n", argv[0]);
            exit(1);
        }

        acnt_id = atoi(argv[1]);
        timeout = 5;

        n = tmaxreadenv("tmax.env", "tmax");
        if (n < 0) {
            fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno);
            exit(1);
        }

        n = tpstart((TPSTART_T *)NULL);
        if (n < 0) {
            fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno);
            exit(1);
        }

        sndbuf = (struct input *)tpalloc("STRUCT", "input", `
                  sizeof(struct input));
        if (sndbuf == NULL) {
            fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        rcvbuf = (char *)tpalloc("STRING", NULL, 0);
        if (rcvbuf == NULL) {
            fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        sndbuf->account_id = acnt_id;
        sndbuf->branch_id = acnt_id;
        strcpy(sndbuf ->phone, TEMP_PHONE);
        strcpy(sndbuf ->address, TEMP_ADDRESS);

        tx_set_transaction_timeout(timeout);
        n = tx_begin();
        if (n < 0)
            fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno);

        n = tpcall("UPDATE", (char *)sndbuf, sizeof(struct input),
                   (char **)&rcvbuf, (long *)&len, TPNOFLAGS);
        if (n < 0) {
            fprintf(stderr, "tpcall fail! tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = tx_commit();
        if (n < 0) {
            fprintf(stderr, "tx commit fail! tx error = %d \n", n);
            tx_rollback();
            tpend();
            exit(1);
        }

        printf("rtn msg = %s\n", rcvbuf);
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}
Server Program

The following is an example of a server program that executes UPDATE to the database.

<update.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/sdl.h>
#include "../sdl/demo.s"

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;
EXEC SQL BEGIN DECLARE SECTION;
        int     account_id;
        int     branch_id;
        char    ssn[15];
        char    phone[15];
        char    address[61];
EXEC SQL END DECLARE SECTION;

UPDATE(TPSVCINFO *msg)
{
        struct input *rcvbuf;
        int     ret;
        long    acnt_id, rcvlen;
        char    *send;

        rcvbuf = (struct input *)(msg->data);
            send = (char *)tpalloc("STRING", NULL, 0);
        if (send == NULL) {
            fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno));
            tpreturn(TPFAIL, 0, (char *)NULL, 0, 0);
        }
        account_id = rcvbuf->account_id;
        branch_id = rcvbuf->branch_id;
}

The following is an example of a server program that executes INSERT to the database.

<insert.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/sdl.h>
#include "../sdl/demo.s"

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;
EXEC SQL BEGIN DECLARE SECTION;
        int     account_id;
        int     branch_id;
        char    ssn[15];
        char    phone[15];
        char    address[61];
EXEC SQL END DECLARE SECTION;

INSERT(msg)
TPSVCINFO  *msg;
{
        struct input *rcvbuf;
        int     ret;
        long    acnt_id;
        char    *send;

        rcvbuf = (struct input *)(msg->data);
        send = (char *)tpalloc("STRING", NULL, 0);
        if (send == NULL) {
            fprintf(stderr, "tpalloc fail errno = %s\n", tpstrerror(tperrno));
            tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS);
        }

        account_id = rcvbuf->account_id;
        branch_id = rcvbuf->branch_id;
        strcpy(phone, rcvbuf->phone);
        strcpy(address, rcvbuf->address);
        strcpy(ssn, "1234567");

        /*  Declare && Open Cursor for Fetch */
        EXEC SQL INSERT INTO ACCOUNT (
            ACCOUNT_ID,
            BRANCH_ID,
            SSN,
            PHONE,
            ADDRESS )
        VALUES (:account_id, :branch_id, :ssn, :phone, :address);

        if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 )
        {
            printf("insert failed sqlcode = %d\n", sqlca.sqlcode);
            tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS);
        }
        strcpy(send, OKMSG);
        tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

4.2. Synchronous mode (heterogeneous)

The following figure shows the program flow for connecting to a heterogeneous database in synchronous mode.

figure 13 2
Flow of Heterogeneous Database Connection (Synchronous Mode)
Program Configuration
  • Common Program

    Program File Description

    demo.s

    SDLFILE.

    sample.m

    Tmax configuration file.

    tmax.env

    Environment file.

    mktable.sql

    SQL script to create a database table.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    update.pc, insert.pc

    Server program.

    Makefile

    Makefile provided by Tmax that must be modified.

Both the client and server programs are the same as described in Synchronous mode (homogeneous). For more information about multi-node configuration, refer to Tmax Administration Guide.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Connection with NULL parameter

    Buffer type

    STRUCT

    Subtype

    The input struct file needs to be compiled using sdlc to create an SDL file.

    Transaction handling

    Specified by client.

  • Server Program

    Feature Description

    Service count

    The UPDATE service requests for the INSERT service.

    Database connection

    Oracle. The database information must be set in the SVRGROUP section in the system configuration file.

System Requirements
Description

Platform

SunOS 5.7 32bit, SunOS 5.8 32bit

Database

Oracle 8.0.5

Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
res         SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60

*NODE
tmax1       TMAXDIR="/user/ tmax ",
            APPDIR="/user/ tmax /appbin",
            PATHDIR = "/user/ tmax /path",
            TLOGDIR = "/user/ tmax /log/tlog",
            ULOGDIR="/user/ tmax /log/ulog",
            SLOGDIR="/user/ tmax /log/slog"

tmax2       TMAXDIR="/user/ tmax ",
            APPDIR="/user/ tmax /appbin",
            PATHDIR = "/user/ tmax /path",
            TLOGDIR = "/user/ tmax /log/tlog",
            ULOGDIR="/user/ tmax /log/ulog",
            SLOGDIR="/user/ tmax /log/slog"

*SVRGROUP
svg1        NODENAME = tmax1, DBNAME = ORACLE,
            OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60",
            TMSNAME = svg1_tms

svg2        NODENAME = tmax2, DBNAME = ORACLE,
            OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60",
            TMSNAME = svg2_tms

*SERVER
update      SVGNAME=svg1
insert      SVGNAME=svg2

*SERVICE
UPDATE      SVRNAME=update
INSERT      SVRNAME=insert

The following is an example of an environment file:

[tmax1]
TMAX_HOST_ADDR=192.168.1.39
TMAX_HOST_PORT=8880
SDLFILE=/user/tmax/sample/sdl/tmax.sdl
TMAX_CONNECT_TIMEOUT=5

4.3. Asynchronous mode (homogeneous)

The following figure shows the program flow for connecting to a homogeneous database in asynchronous mode.

figure 11 4
Flow of Homogeneous Database Connection (Asynchronous Mode)
Program Configuration
  • Common Program

    Program File Description

    demo.s

    SDLFILE.

    sample.m

    Tmax configuration file.

    tmax.env

    Environment file.

    mktable.sql

    SQL script to create a database table.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    update.pc

    Server program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Features
  • Client Program

    Feature Description

    Tmax connection

    Connection with NULL parameter

    Buffer type

    STRUCT

    Subtype

    The input struct file needs to be compiled using sdlc to create an SDL file.

    Transaction handling

    Specified by client.

  • Server Program

    Feature Description

    Service count

    The UPDATE service is requested.

    Database connection

    Oracle. The database information must be set in the SVRGROUP section in the system configuration file.

System Requirements
Description

Platform

SunOS 5.7 32bit

Database

Oracle 8.0.5

Struct Buffer

The following is an example of a struct buffer:

<demo.s>

struct input {
        int     account_id;
        int     branch_id;
        char    phone[15];
        char    address[61];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

<sample.m>

*DOMAIN
res         SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60

*NODE
tmax        TMAXDIR="/user/ tmax ",
            APPDIR="/user/ tmax /appbin",
            PATHDIR = "/user/ tmax /path",
            TLOGDIR = "/user/ tmax /log/tlog",
            ULOGDIR="/user/ tmax /log/ulog",
            SLOGDIR="/user/ tmax /log/slog"

*SVRGROUP
svg1        NODENAME = tmax, DBNAME = ORACLE,
            OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60",
            TMSNAME = svg1_tms

*SERVER
update      SVGNAME=svg1

*SERVICE
UPDATE      SVRNAME=update

The following is an example of an environment file:

<tmax.env>

[tmax]
TMAX_HOST_ADDR=192.168.1.39
TMAX_HOST_PORT=8880
SDLFILE=/user/tmax/sample/sdl/tmax.sdl
TMAX_CONNECT_TIMEOUT=5
Database Script

The following is an example of an SQL script that creates a database table:

<mktable.sql>

$ORACLE_HOME/bin/sqlplus bmt/bmt <<!
drop table ACCOUNT;
create table ACCOUNT (
        ACCOUNT_ID  integer,
        BRANCH_ID   integer not null,
        SSN     char(13) not null,
        BALANCE     number,
        ACCT_TYPE   char(1),
        LAST_NAME   char(21),
        FIRST_NAME  char(21),
        MID_INIT    char(1),
        PHONE       char(15),
        ADDRESS     char(61),
        CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID)
);
quit
!
Client Program

The following is an example of a client program:

<client.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

#define TEMP_PHONE "6283-2114"
#define TEMP_ADDRESS "Korea"

int main(int argc, char *argv[])
{
        struct input *sndbuf;
        char    *rcvbuf;
        int acnt_id, n, cd, timeout;
        long    len;

        if (argc != 2) {
            fprintf(stderr, "Usage:%s account_id \n", argv[0]);
            exit(1);
        }

        acnt_id = atoi(argv[1]);
        timeout = 5;

        n = tmaxreadenv("tmax.env", "tmax");
        if (n < 0) {
            fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno);
            exit(1);
        }

        n = tpstart((TPSTART_T *)NULL);
        if (n < 0) {
            fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno);
            exit(1);
        }

        sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input));
        if (sndbuf == NULL) {
            fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        rcvbuf = (char *)tpalloc("STRING", NULL, 0);
        if (rcvbuf == NULL) {
            fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        sndbuf->account_id = acnt_id;
        sndbuf->branch_id = acnt_id;
        strcpy(sndbuf->phone, TEMP_PHONE);
        strcpy(sndbuf->address, TEMP_ADDRESS);
        tx_set_transaction_timeout(timeout);
        n = tx_begin();
        if (n < 0)
            fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno);

        cd = tpacall("UPDATE", (char *)sndbuf, sizeof(struct input), TPNOFLAGS);
        if (cd < 0) {
            fprintf(stderr, "tpacall fail! tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = tpgetrply(&cd, (char **)&rcvbuf, (long *)&len, TPNOFLAGS);
        if (n < 0) {
            fprintf(stderr, "tpgetrply fail! tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = tx_commit();
        if (n < 0) {
            fprintf(stderr, "tx commit fail! tx error = %d \n", n);
            tx_rollback();
            tpend();
            exit(1);
        }
        printf("rtn msg = %s\n", rcvbuf);
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}
Server Program

The following is an example of a server program:

<update.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;

EXEC SQL BEGIN DECLARE SECTION;
        int     account_id;
        int     branch_id;
        char    ssn[15];
        char    phone[15];
        char    address[61];
EXEC SQL END DECLARE SECTION;

UPDATE(TPSVCINFO *msg)
{
        struct input *rcvbuf;
        int     ret, cd;
        long    acnt_id, rcvlen;
        char    *send;

        rcvbuf = (struct input *)(msg->data);
        send = (char *)tpalloc("STRING", NULL, 0);
        if (send == NULL) {
            fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno));
            tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS);
        }
        account_id = rcvbuf->account_id;
        branch_id = rcvbuf->branch_id;
        strcpy(phone, rcvbuf->phone);
        strcpy(address, rcvbuf->address);
        strcpy(ssn, "1234567");

        EXEC SQL UPDATE ACCOUNT
        SET BRANCH_ID = :branch_id,
        PHONE = :phone,
        ADDRESS = :address,
        SSN = :ssn
        WHERE ACCOUNT_ID = :account_id;

        if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) {
            fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode);
            tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS);
        }
        strcpy(send, OKMSG);
        tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

4.4. Interactive mode (homogeneous)

The following figure shows the program flow for connecting to a homogeneous database in interactive mode.

figure 13 3
Flow of Homogeneous Database Connection (Interactive Mode)
Program Configuration
  • Common Program

    Program File Description

    demo.s

    SDLFILE.

    sample.m

    Tmax configuration file.

    tmax.env

    Environment file.

    mktable.sql

    SQL script to create a database table.

  • Client Program

    Program File Description

    client.c

    Client program.

  • Server Program

    Program File Description

    update.pc

    Server program.

    Makefile

    Makefile provided by Tmax that must be modified.

Program Configuration
  • Client Program

    Feature Description

    Tmax connection

    Connection with NULL parameter

    Buffer type

    STRUCT

    Subtype

    The input struct file needs to be compiled using sdlc to create an SDL file (Required for running the application).

    Transaction handling

    Specified by client.

  • Server Program

    Feature Description

    Service count

    The UPDATE service is requested.

    Database connection

    Oracle. The database information must be set in the SVRGROUP section in the Tmax configuration file.

System Requirements
Description

Platform

SunOS 5.7 32bit

Database

Oracle 8.0.5

Struct Buffer

The following is an example of a struct buffer:

<demo.s>

struct input {
        int     account_id;
        int     branch_id;
        char    phone[15];
        char    address[61];
};
Tmax Configuration File

The following is an example of a Tmax configuration file:

*DOMAIN
res   SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60


*NODE
tmax        TMAXDIR="/user/ tmax ",
            APPDIR="/user/ tmax /appbin",
            PATHDIR = "/user/ tmax /path",
            TLOGDIR = "/user/ tmax /log/tlog",
            ULOGDIR="/user/ tmax /log/ulog",
            SLOGDIR="/user/ tmax /log/slog"

*SVRGROUP
svg1        NODENAME = tmax, DBNAME = ORACLE,
            OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60",
            TMSNAME = svg1_tms

*SERVER
update      SVGNAME=svg1, CONV=YES

*SERVICE
UPDATE      SVRNAME= update

The following is an example of an environment file:

<tmax.env>

[tmax]
TMAX_HOST_ADDR=192.168.1.39
TMAX_HOST_PORT=8880
SDLFILE=/user/tmax/sample/sdl/tmax.sdl
TMAX_CONNECT_TIMEOUT=5
Database Script

The following is an example of an SQL script that creates a database table:

<mktable.sql>

$ORACLE_HOME/bin/sqlplus bmt/bmt <<!
drop table ACCOUNT;
create table ACCOUNT (
        ACCOUNT_ID  integer,
        BRANCH_ID   integer not null,
        SSN     char(13) not null,
        BALANCE     number,
        ACCT_TYPE   char(1),
        LAST_NAME   char(21),
        FIRST_NAME  char(21),
        MID_INIT    char(1),
        PHONE       char(15),
        ADDRESS     char(61),
        CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID)
);
quit
!
Client Program

The following is an example of a client program:

<client.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

#define TEMP_PHONE "6283-2115"
#define TEMP_ADDRESS "Korea"

void main(int argc, char *argv[])
{
        struct input *sndbuf;
        char    *rcvbuf;
        int acntid, timeout;
        long revent, rcvlen;
        int cd, n;

        if (argc != 2) {
            fprintf(stderr, "Usage:%s acntid\n", argv[0]);
            exit(1);
        }

        acntid = atoi(argv[1]);
        timeout = 5;
        n = tmaxreadenv("tmax.env", "tmax");
        if (n < 0) {
            fprintf(stderr, "tmaxreadenv fail tperrno = %d\n", tperrno);
            exit(1);
        }

        n = tpstart((TPSTART_T *)NULL);
        if (n < 0) {
            fprintf(stderr, "tpstart fail tperrno = %s\n", tperrno);
            exit(1);
        }
        printf("tpstart ok!\n");
        sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input));
        if (sndbuf == NULL) {
            fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        rcvbuf = (char *)tpalloc("CARRAY", NULL, 0);
        if (rcvbuf == NULL) {
            fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        sndbuf->account_id = acntid;
        sndbuf->branch_id = acntid;
        strcpy(sndbuf->phone, TEMP_PHONE);
        strcpy(sndbuf->address, TEMP_ADDRESS);

        tx_set_transaction_timeout(timeout);
        n = tx_begin();
        if (n < 0)
            fprintf(stderr, "tx begin fail tx error = %d\n", n);
        printf("tx begin ok!\n");

        cd = tpconnect("UPDATE", (char *)sndbuf, 0, TPSENDONLY);
        if (cd < 0) {
            fprintf(stderr, "tpconnect fail tperrno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        while (1) {
            n = tpsend(cd, (char *)sndbuf, sizeof(struct input), TPRECVONLY,
                       &revent);
            if (n < 0) {
                fprintf(stderr, "tpsend fail revent = 0x%08x\n", revent);
             tx_rollback();
                tpend();
                exit(1);
            }
            printf("tpsend ok\n");

            n = tprecv(cd, (char **)&rcvbuf, (long *)&rcvlen, TPNOTIME, &revent);
            if (n < 0 && revent != TPEV_SENDONLY) {
                fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent);
                tx_rollback();
                tpend();
                exit(1);
            }
            printf("tprecv ok\n");
            sndbuf->account_id++;

            if (revent != TPEV_SENDONLY)
            break;
        }
        n = tprecv(cd, (char **)&rcvbuf, (long *)&rcvlen, TPNOTIME, &revent);
        if (n < 0 && revent != TPEV_SVCSUCC) {
            fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent);
            tx_rollback();
            tpend();
            exit(1);
        }
        printf("rcvbuf = [%s]\n", rcvbuf);

        n = tx_commit();
        if (n < 0) {
            fprintf(stderr, "tx commit fail tx error = %d\n", n);
            tx_rollback();
            tpend();
            exit(1);
        }
        printf("tx commit ok!\n");
        printf("rtn msg = %s\n", rcvbuf);
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}
Server Program

The following is an example of a server program:

<update.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include "../sdl/demo.s"

void _db_work();

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;
EXEC SQL BEGIN DECLARE SECTION;
        int     account_id;
        int     branch_id;
        char    ssn[15];
        char    phone[15];
        char    address[61];
EXEC SQL END DECLARE SECTION;

struct input *rcvbuf;

UPDATE(TPSVCINFO *msg)
{
        int     ret, count;
        long    acnt_id;
        long    revent, rcvlen, flag;
        char    *send;

        rcvbuf = (struct input *)tpalloc("STRUCT", "input", 0);
        send = (char *)tpalloc("CARRAY", NULL, 0);

        count = 1;
        flag = 0;

        while (1) {
            ret = tprecv(msg->cd, (char **)&rcvbuf, &rcvlen, TPNOTIME, &revent);
            if (ret < 0 && revent != TPEV_SENDONLY) {
                fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent);
                tpreturn(TPFAIL, -1, (char *)rcvbuf, 0, TPNOFLAGS);
            }
            printf("tprecv ok!\n");

            if (count == 10) {
                flag &= ~TPRECVONLY;
                flag |= TPNOTIME;
            }
            else
                flag |= TPRECVONLY;

            ret = tpsend(msg->cd, (char *)send, strlen(send), flag, &revent);
            if (ret < 0) {
                fprintf(stderr, "tpsend fail revent = 0x%08x\n", revent);
                tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS);
            }
            printf("tpsend ok!\n");
            _db_work();

            /* break after 10 iterations */
            if (count == 10)
                break;

            count++;
        }

        strcpy(send, OKMSG);
        printf("tpreturn ok!\n");
        tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

void _db_work() {
        account_id = rcvbuf->account_id;
        branch_id = rcvbuf->branch_id;
        strcpy(phone, rcvbuf->phone);
        strcpy(address, rcvbuf->address);
        strcpy(ssn, "1234567");

        EXEC SQL UPDATE ACCOUNT
        SET BRANCH_ID = :branch_id,
            PHONE = :phone,
            ADDRESS = :address,
            SSN = :ssn
            WHERE ACCOUNT_ID = :account_id;

        if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) {
            fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode);
            tpreturn(TPFAIL, -1, (char *)NULL, 0, 0);
        }
}

5. Program Using TIP

TIP (Tmax Information Provider) is a function process that handles TIPSVC. The following features can be performed using TIP.

  • System environment information check: Static environment information of a system can be checked.

  • System statistical information check: Status of each process can be checked while a system is operating.

  • System operation management: Processes are started or terminated.

5.1. TIP Structure

The TIP server has the SYS_SVR server type and is included in the TIP server group. The TIP server receives a request from a client or server, transfers the request to CLH/TMM, and then returns the result to the requester. The TIP server uses field keys to handle the service. The client or server saves data to be requested to a field buffer, sends a request, and then receives the result with the field buffer.

  • CHLOG section (log level change)

    CHLOG is the section in which the log levels of TMM, CLH, TMS, and SVR are changed. CHLOG performs the same action as chlog in tmadmin.

    Property Description

    TIP_OPERATION (string)

    Set to GET.

    TIP_SEGMENT (string)

    Set to ADMINISTRATION.

    TIP_SECTION (string)

    Set to CHLOG.

    TIP_MODULE (int)

    Sets a module to dynamically change log. Options are:

    • TIP_TMM

    • TIP_CLH

    • TIP_TMS

    • TIP_SVR

    TIP_FLAGS (int)

    Sets flags. Options are:

    • TIP_VFLAG

    • TIP_GFLGA

    • TIP_NFLAG

    TIP_SVRNAME (string)

    Corresponding server name. Set only when TIP_FLAGS is TIP_VFLAG.

    TIP_SVGNAME (string)

    Corresponding server group name. Set only when TIP_FLAGS is TIP_GFLAG.

    TIP_NODENAME (string)

    Corresponding node name. Set only when TIP_FLAGS is TIP_NFLAG.

    TIP_LOGLVL (string)

    Log level. Value must be in lowercase letters. The result value is set in TIP_ERROR. Options are:

    • compact

    • basic

    • detail

    • debug1

    • debug2

    • debug3

    • debug4

    TIP_ERROR (int)

    Error value. Options are:

    • TIPESVCFAIL: corresponding service was not handled successfully

    • TIPEOS: memory allocation failed

    • TIPEBADFLD: value of TIP_MODULE is not set

  • CHTRC section

    TMAX_TRACE of TMS and SPR are specified to modify the trace log options in the CHTRC section. CHTRC performs the same action as chtrc in tmadmin.

    Property Description

    TIP_OPERATION (string)

    Set to GET.

    TIP_SEGMENT (string)

    Set to ADMINISTRATION.

    TIP_SECTION (string)

    Set to CHTRC.

    TIP_FLAGS (int)

    Sets flags. Options are:

    • TIP_PFLAG

    • TIP_VFLAG

    • TIP_GFLAG

    • TIP_NFLAG

    TIP_SPRI (int)

    Sets spri. Set only when TIP_FLAGS is TIP_PFLAG.

    TIP_SVGNAME (string)

    Corresponding server group name. Set only when TIP_FLAGS is TIP_GFLAG.

    TIP_NODENAME (string)

    Corresponding node name. Set only when TIP_FLAGS is TIP_NFLAG.

    TIP_SPEC (string)

    Sets filter spec, receiver spec, and trigger spec. The result value is set in TIP_ERROR.

    TIP_ERROR (int)

    Error value. Options are:

    • TIPESVCFAIL: corresponding service was not successfully handled

    • TIPEOS: memory allocation is failed

    • TIPEBADFLD: value of TIP_MODULE is not set

The following must be included in requests to TIPSVC.

  • Operation (TIP_OPERATION)

    Value Description

    GET

    To check statistical information and static configuration information of the system or to operate and manage a system (BOOT/DOWN).

    SET

    To change system settings. Currently, only GET is supported.

  • Segment (TIP_SEGMENT)

    Used to determine which function to execute. The following can be set in the TIP_SEGMENT field:

    Value Description

    CONFIGURATION

    Checks the static configuration information of the system.

    STATISTICS

    Checks the statistical information of the system during runtime.

    ADMINISTRATION

    Checks the operational information of the system (BOOT/DOWN).

  • Section (TIP_SECTION)

    Used to specify detailed setting items under the segments:

    Value Description

    CONFIGURATION

    DOMAIN, NODE, SVRGROUP, SERVER, SERVICE, ROUTING, RQ, GATEWAY

    STATISTICS

    NODE, TPROC, SPR, SERVICE, RQ, TMGW, NTMGW, TMS, TMMS, CLHS, SERVER(SVR)

    ADMINISTRATION

    BOOT, DOWN, CHLOG, CHTRC

  • Command (TIP_CMD)

    Used only when TIP_SECTION is ADMINISTRATION.

    Value Description

    TIP_BOOT

    Starts the Tmax system.

    TIP_DOWN

    Shuts down the Tmax system.

5.2. TIP Usage

The following describes how to use TIP and how to check an error:

Using TIP
  • Environment setting

    A user does not need to write a service because the TIP server is a function process provided by Tmax. However, a user must register the TIP server in a configuration file.

    The following is an example of setting an environment.

    *DOMAIN
    res             ..., TIPSVC = TIPSVC
    
    *NODE
    tmaxs1       ...
    
    *SVRGROUP
    tsvg            ..., SVGTYPE = TIP
    
    *SERVER
    TIP             SVGNAME = tsvg, SVRTYPE = SYS_SVR
    • TIPSVC is registered in the DOMAIN section. If unregistered, TIPSVC is registered by default.

    • A TIP server group (SVGTYPE=TIP) is registered in the SVRGROUP section.

    • A TIP server (SVRTYPE=SYS_SVR) is registered in the SERVER section.

      Since MIN and MAX can be set to a value that is greater than or equal to 1 for TIP servers from Tmax 5 SP2 Fix #1, multiple TIP servers can start and TIPSVC requests can be processed in parallel.

  • System access

    A user must set .tpadmin in the usrname property of the TPSTART_T structure when accessing the Tmax system. usrname is set only when TIP_SEGMENT is ADMINISTRATION. If usrname is set incorrectly, the TIPEAUTH error is set in the TIP_ERROR field.

     strcpy(tpinfo->usrname, “.tpadmin”);
  • Buffer allocation

    A client or a server program must allocate a field key buffer for a request because the TIP server uses field keys to handle a service.

  • TIP request properties

    Property Description

    TIP_OPERATION

    Changes and checks system environment information.

    TIP_SEGMENT

    Checks information for system operation and management.

    TIP_SECTION

    Detailed property settings in SEGMENT.

    TIP_CMD

    Set only when TIP_SEGMENT is ADMINISTRATION.

    TIP_NODENAME

    Set only for multiple nodes. If only a single node exists, TIP_NODENAME is set to a local node by default. If it is incorrectly set, the TPEINVAL error occurs.

  • TIPSVC request

    After the required properties for TIP are set, set the configured field buffer to sndbuf and use tpcall or tpacall to send the TIPSVC request. Both client and server can request a service, and transactions are not supported.

  • Result reception

    The service result is saved in a reception field key buffer.

Error Check
  • If successfully handled

    The TIP_ERROR property of a reception field key buffer is set to 0.

  • If an error occurs

    Error Description

    TIP_STATUS

    Detailed error information set in TIP_ERROR can be checked.

    TIP_BADFIELD

    Field that caused the error can be checked.

    TIP_ERROR

    Value greater than 0 is set in TIP_ERROR of a reception field key buffer. It can be checked in /usrinc/tip.h.

    The following are the error values that can be set in TIP_ERROR.

    TIPNOERROR : No error occurred. TIPEBADFLD : Invalid field key issued. In general, TIPEBADFLD is set when a field key not compiled by the fdlc utility. TIPEIMPL : Unavailable feature is requested. TIPEAUTH : Service not allowed under current privileges. TIPEOS : OS or system error caused by a memory allocation failure, connection to Tmax system failed, or unstable network status. TIPENOENT : Tried to access a nonexistent property. ** TIPESVCFAIL : tpreturn() is called to TPFAIL due to a TIP service routine error.

5.3. TIP Usage Example

The following describes examples of using TIP.

Configuration File

The following example uses a single node:

<cfg.m>

*DOMAIN
res          SHMKEY=78850,     MAXUSER=200, MINCLH=1, MAXCLH=5,
             TPORTNO=8850,     BLOCKTIME=60, TXTIME=50, RACPORT=3355

*NODE
tmaxh4         TMAXDIR="/data1/starbj81/tmax",
               APPDIR="/data1/starbj81/tmax/appbin",
               PATHDIR ="/data1/starbj81/tmax/path",
               TLOGDIR ="/data1/starbj81/tmax/log/tlog",
               ULOGDIR="/data1/starbj81/tmax/log/ulog",
               SLOGDIR="/data1/starbj81/tmax/log/slog"

*SVRGROUP
tsvg          NODENAME = "tmaxh4", SVGTYPE=TIP
svg1          NODENAME = "tmaxh4"

*SERVER
TIP            SVGNAME=tsvg, SVRTYPE=SYS_SVR, MIN=1, MAX=1
svr            SVGNAME=svg1, MIN=1

*SERVICE
TOUPPER        SVRNAME=svr

The following example uses multiple nodes:

<cfg.m>

*DOMAIN
tmax          SHMKEY=98850,
              TPORTNO=8850,
              BLOCKTIME=60,
              RACPORT=3355,
              MAXUSER=10

*NODE
Tmaxh4         TMAXDIR="/data1/starbj81/tmax",
               APPDIR="/data1/starbj81/tmax/appbin",
               PATHDIR = "/data1/starbj81/tmax/path",
               TLOGDIR = "/data1/starbj81/tmax/log/tlog",
               ULOGDIR="/data1/starbj81/tmax/log/ulog",
               SLOGDIR="/data1/starbj81/tmax/log/slog"

tmaxh2         TMAXDIR="/data1/starbj81/tmax",
               APPDIR="/data1/starbj81/tmax/appbin",
               PATHDIR = "/data1/starbj81/tmax/path",
               TLOGDIR = "/data1/starbj81/tmax/log/tlog",
               ULOGDIR="/data1/starbj81/tmax/log/ulog",
               SLOGDIR="/data1/starbj81/tmax/log/slog"

*SVRGROUP
tsvg          NODENAME = "tmaxh4", SVGTYPE=TIP
svg1          NODENAME = "tmaxh4", COUSIN = "svg2"
svg2          NODENAME = "tmaxh2"


*SERVER
TIP          SVGNAME=tsvg, SVRTYPE=SYS_SVR, MIN=1, MAX=1
svr          SVGNAME=svg1, MIN=1, MAX=5

*SERVICE
TOUPPER       SVRNAME=svr, ROUTING = "rout1"

*ROUTING
rout1          FIELD="STRING", RANGES = "'bbbbbbb'-'ccccccc' : svg1, * :
               svg2
Field Key Table

The following is an example of a field key table:

< tip.f >

#
#       common field
#
# name          number  type    flags   comments
*base 16000001
TIP_OPERATION   0       string
TIP_SEGMENT     1       string
TIP_SECTION     2       string
TIP_NODE        3       string
TIP_OCCURS      4       int
TIP_FLAGS       5       int
TIP_CURSOR      6       string
TIP_SESTM       7       int
TIP_ERROR       8       int
TIP_STATE       9       int
TIP_MORE        10      int
TIP_BADFIELD    11      string
TIP_CMD         12      string
TIP_CLID        13      int
TIP_MSG         14      string

#
#       DOMAIN section fields
#
# name                  number  type    flags   comments
*base 16000100
TIP_NAME                0       string
TIP_SHMKEY              1       int
TIP_MINCLH              2       int
TIP_MAXCLH              3       int
TIP_MAXUSER             4       int
TIP_TPORTNO             5       int
TIP_RACPORT             6       int
TIP_MAXSACALL           7       int
TIP_MAXCACALL           8       int
TIP_MAXCONV_NODE        9       int
TIP_MAXCONV_SERVER      10      int
TIP_CMTRET              11      int
TIP_BLOCKTIME           12      int
TIP_TXTIME              13      int
TIP_IDLETIME            14      int
TIP_CLICHKINT           15      int
TIP_NLIVEINQ            16      int
TIP_SECURITY            17      string
TIP_OWNER               18      string
TIP_CPC                 19      int
#TIP_LOGINSVC           20      string
#TIP_LOGOUTSVC          21      string
TIP_NCLHCHKTIME         22      int
TIP_DOMAINID            23      int
TIP_IPCPERM             24      int
TIP_MAXNODE             25      int
TIP_MAXSVG              26      int
TIP_MAXSVR              27      int
TIP_MAXSVC              28      int
TIP_MAXSPR              29      int
TIP_MAXTMS              30      int
TIP_MAXCPC              31      int
TIP_MAXROUT             32      int
TIP_MAXROUTSVG          33      int
TIP_MAXRQ               34      int
TIP_MAXGW               35      int
TIP_MAXCOUSIN           36      int
TIP_MAXCOUSINSVG        37      int
TIP_MAXBACKUP           38      int
TIP_MAXBACKUPSVG        39      int
TIP_MAXTOTALSVG         40      int
TIP_MAXPROD             41      int
TIP_MAXFUNC             42      int
TIP_TXPENDINGTIME       43      int
TIP_NO                  44      int
TIP_TIPSVC              45      string
TIP_NODECOUNT           46      int
TIP_SVGCOUNT            47      int
TIP_SVRCOUNT            48      int
TIP_SVCCOUNT            49      int
TIP_COUSIN_COUNT                50      int
TIP_BACKUP_COUNT                51      int
TIP_ROUT_COUNT          52      int
TIP_STYPE               53      string
TIP_VERSION             54      string
TIP_EXPDATE             55      string
TIP_DOMAINCOUNT         56      int
TIP_RSVG_GCOUNT         57      int
TIP_RSVG_COUNT          58      int
TIP_CSVG_GCOUNT         59      int
TIP_CSVG_COUNT          60      int
TIP_BSVG_GCOUNT         61      int
TIP_BSVG_COUNT          62      int
TIP_PROD_COUNT          63      int
TIP_FUNC_COUNT          64      int
TIP_SHMSIZE             65      int
TIP_CRYPT               66      string
TIP_DOMAIN_TMMLOGLVL    67      string
TIP_DOMAIN_CLHLOGLVL    68      string
TIP_DOMAIN_TMSLOGLVL    69      string
TIP_DOMAIN_LOGLVL       70      string
TIP_DOMAIN_MAXTHREAD    71      int

#
#       NODE section fields
#
# name          number  type    flags   comments
*base 16000200
#TIP_NAME       0       string
TIP_DOMAINNAME  1       string
#TIP_SHMKEY     2       int
#TIP_MINCLH     3       int
#TIP_MAXCLH     4       int
TIP_CLHQTIMEOUT 5       int
#TIP_IDLETIME   6       int
#TIP_CLICHKINT  7       int
#TIP_TPORTNO    8       int
#TIP_TPORTNO2   9       int
#TIP_TPORTNO3   10      int
#TIP_TPORTNO4   11      int
#TIP_TPORTNO5   12      int
#TIP_RACPORT    13      int
#TIP_TMAXPORT   14      string
TIP_CMPRPORT    15      string
TIP_CMPRSIZE    16      int
#TIP_MAXUSER    17      int
TIP_TMAXDIR     18      string
TIP_TMAXHOME    19      string
TIP_APPDIR      20      string
TIP_PATHDIR     21      string
TIP_TLOGDIR     22      string
TIP_SLOGDIR     23      string
TIP_ULOGDIR     24      string
TIP_ENVFILE     25      string
#TIP_LOGINSVC   26      string
#TIP_LOGOUTSVC  27      string
TIP_IP          28      string
#TIP_PEER       29      string
TIP_TMMOPT      30      string
TIP_CLHOPT      31      string
#TIP_IPCPERM    32      int
#TIP_MAXSVG     33      int
#TIP_MAXSVR     34      int
#TIP_MAXSPR     35      int
#TIP_MAXTMS     36      int
#TIP_MAXCPC     37      int
TIP_MAXGWSVR    38      int
TIP_MAXRQSVR    39      int
TIP_MAXGWCPC    40      int
TIP_MAXRQCPC    41      int
TIP_CPORTNO     42      int
TIP_REALSVR     43      string
TIP_RSCPC       44      int
TIP_AUTOBACKUP  45      int
TIP_HOSTNAME    46      string
TIP_NODETYPE    47      int
TIP_CPU         48      int
#TIP_MAXRSTART  49      int
#TIP_GPERIOD    50      int
#TIP_RESTART    51      int
TIP_CURCLH      49      int
TIP_LIVECTIME   50      string
TIP_NODE_TMMLOGLVL      51      string
TIP_NODE_CLHLOGLVL      52      string
TIP_NODE_TMSLOGLVL      53      string
TIP_NODE_LOGLVL         54      string
TIP_NODE_MAXTHREAD      55      int
TIP_EXTPORT             56      int
TIP_EXTCLHPORT          57      int
TIP_MSGSIZEWARN 58      int
TIP_MSGSIZEMAX  59      int


#
#       SVRGROUP section fields
#
# name          number  type    flags   comments
*base 16000300
#TIP_NAME       0       string
#TIP_NODENAME   1       string
TIP_SVGTYPE     2       string
#TIP_PRODNAME   3       string
TIP_COUSIN      4       string
TIP_BACKUP      5       string
TIP_LOAD        6       int
#TIP_APPDIR     7       string
#TIP_ULOGDIR    8       string
TIP_DBNAME      9       string
TIP_OPENINFO    10      string
TIP_CLOSEINFO   11      string
TIP_MINTMS      12      int
#TIP_MAXTMS     13      int
TIP_TMSNAME     14      string
#TIP_SECURITY   15      string
#TIP_OWNER      16      string
#TIP_ENVFILE    17      string
#TIP_CPC                18      int
TIP_XAOPTION            19      string
TIP_SVG_TMSTYPE         20      string
TIP_SVG_TMSOPT          21      string
TIP_SVG_TMSTHREADS      22      int
TIP_SVG_TMSLOGLVL       23      string
TIP_SVG_LOGLVL          24      string
TIP_NODENAME            25      string

#
#       SERVER section fields
#
# name          number  type    flags   comments
*base 16000350
#TIP_NAME       0       string
TIP_SVGNAME     1       string
#TIP_NODENAME   2       string
TIP_CLOPT       3       string
TIP_SEQ         4       int
TIP_MIN         5       int
TIP_MAX         6       int
#TIP_ULOGDIR    7       string
TIP_CONV        8       int
TIP_MAXQCOUNT   9       int
TIP_ASQCOUNT    10      int
TIP_MAXRSTART   11      int
TIP_GPERIOD     12      int
TIP_RESTART     13      int
TIP_SVRTYPE     14      string
#TIP_CPC                15      int
TIP_SCHEDULE    16      int
#TIP_MINTHR     17      int
#TIP_MAXTHR     18      int
TIP_TARGET      19      string
TIP_DEPEND      20      string
TIP_CASCADE     21      int
TIP_PROCNAME    22      string
TIP_LIFESPAN    23      string
TIP_DDRI        24      string
TIP_CURSVR      25      int
TIP_SVGNO       26      int
TIP_SVR_LOGLVL  27      string


#
#       SERVICE section fields
#
# name          number  type    flags   comments
*base 16000400
#TIP_NAME       0       string
TIP_SVRNAME     1       string
TIP_PRI         2       int
TIP_SVCTIME     3       int
TIP_ROUTING     4       string
TIP_EXPORT      5       int
TIP_AUTOTRAN    6       int

#
#       ROUTING section fields
#
# name          number  type    flags   comments
*base 16000425
#TIP_NAME       0       string
TIP_FLDTYPE     1       string
TIP_RANGES      2       string
TIP_SUBTYPE     3       string
TIP_ELEMENT     4       string
TIP_BUFTYPE     5       string
TIP_OFFSET      6       int
TIP_FLDLEN      7       int
#TIP_FLDOFFSET  8       int

#
#       RQ section fields
#
# name          number  type    flags   comments
*base 16000450
#TIP_NAME       0       string
#TIP_SVGNAME    1       string
TIP_PRESVC      2       string
TIP_QSIZE       3       int
TIP_FILEPATH    4       string
TIP_BOOT        5       string
TIP_FSYNC       6       int
TIP_BUFFERING   7       int
#TIP_ENQSVC     8       int
#TIP_FAILINTERVAL 9     int
#TIP_FAILRETRY  10      int
#TIP_FAILSVC    11      string
#TIP_AFTERSVC   12      string

#
#       GATEWAY section fields
#
# name                  number  type    flags   comments
*base 16000500
#TIP_NAME               0       string
TIP_GWTYPE              1       string
TIP_PORTNO              2       int
#TIP_CPC                        3       int
TIP_RGWADDR             4       string
TIP_RGWPORTNO           5       int
#TIP_BACKUP             6       string
#TIP_NODENAME           7       string
TIP_KEY                 8       string
TIP_BACKUP_RGWADDR      9       string
TIP_BACKUP_RGWPORTNO    10      int
TIP_TIMEOUT             11      int
TIP_DIRECTION           12      string
TIP_MAXINRGW            13      int
TIP_GWOWNER             15      string
TIP_RGWOWNER            16      string
TIP_RGWPASSWD           17      string
TIP_PTIMEOUT            18      int
TIP_PTIMEINT            19      int

#
#       FUNCTION section fields
#
# name          number  type    flags   comments
*base 16000550
#TIP_NAME       0       string
#TIP_SVRNAME    1       string
TIP_FQSTART     2       int
TIP_FQEND       3       int
TIP_ENTRY       4       string


#
#       STATISTICS segment fields
#
# name          number  type    flags   comments
*base 16000600
#TIP_NAME       0       string
TIP_STATUS      1       string
TIP_STIME       2       string
TIP_TTIME       3       int
TIP_SVC_STIME   4       int
TIP_COUNT       5       int
#TIP_NO         6       int
TIP_NUM_FREE    7       int
TIP_NUM_REPLY   8       int
TIP_NUM_FAIL    9       int
TIP_NUM_REQ     10      int
TIP_ENQ_REQS    11      int
TIP_DEQ_REQS    12      int
TIP_ENQ_REPLYS  13      int
TIP_DEQ_REPLYS  14      int
TIP_CLHNO       15      int
TIP_SVR_NAME    16      string
TIP_SVC_NAME    17      string
TIP_AVERAGE     18      float
TIP_QCOUNT      19      int
TIP_CQCOUNT     20      int
TIP_QAVERAGE    21      float
TIP_MINTIME     22      float
TIP_MAXTIME     23      float
TIP_FAIL_COUNT  24      int
TIP_ERROR_COUNT 25      int
TIP_PID         26      int
TIP_TOTAL_COUNT 27      int
TIP_TOTAL_SVCFAIL_COUNT 28      int
TIP_TOTAL_ERROR_COUNT   29      int
TIP_TOTAL_AVG   30      float
TIP_TOTAL_RUNNING_COUNT 31      int
TIP_TMS_NAME    32      string
TIP_SVG_NAME    33      string
TIP_SPRI        34      int
TIP_TI_THRI     35      int
TIP_TI_AVG      36      float
TIP_TI_XID      37      string
TIP_TI_XA_STATUS        38      string
TIP_GW_NAME     39      string
TIP_GW_NO       40      int
TIP_GW_HOSTN    41      string
TIP_GW_CTYPE    42      string
TIP_GW_CTYPE2   43      string
TIP_GW_IPADDR   44      string
TIP_GW_PORT     45      int
TIP_GW_STATUS   46      string

#
#       ADMIN segment fields
#
# name          number  type    flags   comments
*base 16000650
TIP_IPADDR      0       string
TIP_USRNAME     1       string
TIP_MODULE      2       int
TIP_LOGLVL      3       string
TIP_SPEC        4       string

#
#       boot time
#
# name          number  type    flags   comments
TIP_BOOTTIME_SEC        5       int
TIP_BOOTTIME_MSEC       6       int

#
#       EXTRA flag fields
#
# name          number  type    flags   comments
*base 16000700
TIP_EXTRA_OPTION        0       int
TIP_SVRI        1       int
TIP_QPCOUNT     2       int
TIP_EMCOUNT     3       int
TIP_SVR_STATUS  4       string

5.4. Program for Checking System Environment Information

The following is an example of a client program that checks system environment information:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/fbuf.h>
#include <usrinc/tip.h>

#define SEC_DOMAIN          1
#define SEC_NODE            2
#define SEC_SVGROUP         3
#define SEC_SERVER          4
#define SEC_SERVICE         5
#define SEC_ROUTING         6
#define SEC_RQ              7
#define SEC_GATEWAY         8

main(int argc, char *argv[])
{
        FBUF    *sndbuf, *rcvbuf;
        TPSTART_T *tpinfo;
        int   i, n, sect;
        long  rcvlen;
        char  nodename[NAMELEN];
        int   pid, count = 0;

        if (argc != 3) {
            printf("Usage: %s section nodename\n", argv[0]);
            printf("section:\n");
            printf("\t1: domain\n");
            printf("\t2: node\n");
            printf("\t3: svrgroup\n");
            printf("\t4: server\n");
            printf("\t5: service\n");
            printf("\t6: routing\n");
            printf("\t7: rq\n");
            printf("\t8: gateway\n");
            exit(1);
        }

        if (!isdigit(argv[3][0])) {
            printf("fork count must be a digit\n");
            exit(1);
        }
        count = atoi(argv[3]);

        sect = atoi(argv[1]);
        if (sect < SEC_DOMAIN || sect > SEC_GATEWAY) {
            printf("out of section [%d - %d]\n", SEC_DOMAIN, SEC_GATEWAY);
            exit(1);
        }

        strncpy(nodename, argv[2], sizeof(nodename) - 1);

        n = tmaxreadenv("tmax.env", "TMAX");
        if (n < 0) {
           fprintf(stderr, "can't read env\n");
           exit(1);
        }

        tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0);
        if (tpinfo == NULL) {
            printf("tpalloc fail tperrno = %d\n", tperrno);
            exit(1);
        }
        strcpy(tpinfo->usrname, ".tpadmin");
        if (tpstart((TPSTART_T *)tpinfo) == -1){
            printf("tpstart fail [%s]\n", tpstrerror(tperrno));
            exit(1);
        }

        if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = fbput(sndbuf, TIP_OPERATION, "GET", 0);
        n = fbput(sndbuf, TIP_SEGMENT, "CONFIGURATION", 0);
        switch (sect) {
            case SEC_DOMAIN:
                n = fbput(sndbuf, TIP_SECTION, "DOMAIN", 0);
                break;
            case SEC_NODE:
                n = fbput(sndbuf, TIP_SECTION, "NODE", 0);
                break;
            case SEC_SVGROUP:
                n = fbput(sndbuf, TIP_SECTION, "SVGROUP", 0);
                break;
            case SEC_SERVER:
                n = fbput(sndbuf, TIP_SECTION, "SERVER", 0);
                break;
            case SEC_SERVICE:
                n = fbput(sndbuf, TIP_SECTION, "SERVICE", 0);
                break;
            case SEC_ROUTING:
                n = fbput(sndbuf, TIP_SECTION, "ROUTING", 0);
                break;
            case SEC_RQ:
                n = fbput(sndbuf, TIP_SECTION, "RQ", 0);
                break;
            case SEC_GATEWAY:
                n = fbput(sndbuf, TIP_SECTION, "GATEWAY", 0);
                break;
        }

        n = fbput(sndbuf, TIP_NODENAME, nodename, 0);

        n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf,  &rcvlen,
                    TPNOFLAGS);
        if (n < 0) {
                printf("tpcall fail [%s]\n", tpstrerror(tperrno));
                fbprint(rcvbuf);
                tpfree((char *)sndbuf);
                tpfree((char *)rcvbuf);
                tpend();
                exit(1);
        }

#if 1
        fbprint(rcvbuf);
#endif

        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}

[Result]

The following is the result (Domain Conf) of the previous program.

$ client 1 tmaxh4
fkey = 217326601, fname = TIP_ERROR, type = int, value = 0
...
fkey = 485762214, fname = TIP_CRYPT, type = string, value = NO
    fkey = 485762215, fname = TIP_DOMAIN_TMMLOGLVL, type = string, value = DEBUG1
    fkey = 485762216, fname = TIP_DOMAIN_CLHLOGLVL, type = string, value = DEBUG2
    fkey = 485762217, fname = TIP_DOMAIN_TMSLOGLVL, type = string, value = DEBUG3
    fkey = 485762218, fname = TIP_DOMAIN_LOGLVL, type = string, value = DEBUG4
    fkey = 217326763, fname = TIP_DOMAIN_MAXTHREAD, type = int, value = 128

5.5. Program for Checking System Statistical Information

The following is an example of a program that checks system statistical information:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <usrinc/atmi.h>
#include <usrinc/fbuf.h>
#include <usrinc/tip.h>

#define SEC_NODE        1
#define SEC_TPROC       2
#define SEC_SPR         3
#define SEC_SERVICE     4
#define SEC_RQ          5
#define SEC_TMS         6
#define SEC_TMMS        7
#define SEC_CLHS        8
#define SEC_SERVER        9

#define NODE_NAME_SIZE 32

main(int argc, char *argv[])
{
        FBUF    *sndbuf, *rcvbuf;
        TPSTART_T *tpinfo;
        int   i, n, sect;
        long  rcvlen;
        char  nodename[NODE_NAME_SIZE];
        int stat;

        if (argc != 3) {
            printf("Usage: %s section node\n", argv[0]);
            printf("section:\n");
            printf("\t1: node\n");
            printf("\t2: tproc\n");
            printf("\t3: spr\n");
            printf("\t4: service\n");
            printf("\t5: rq\n");
            printf("\t6: tms\n");
            printf("\t7: tmms\n");
            printf("\t8: clhs\n");
            printf("\t9: server\n");
            exit(1);
        }

        sect = atoi(argv[1]);
        if (sect < SEC_NODE || sect > SEC_CLHS) {
            printf("out of section [%d - %d]\n",SEC_NODE, SEC_TMMS);
            exit(1);
        }

        memset(nodename, 0x00, NODE_NAME_SIZE);
        strncpy(nodename, argv[2], NODE_NAME_SIZE - 1);

        n = tmaxreadenv("tmax.env", "TMAX");
        if (n < 0) {
           fprintf(stderr, "can't read env\n");
           exit(1);
        }

        tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0);
        if (tpinfo == NULL) {
            printf("tpalloc fail tperrno = %d\n", tperrno);
            exit(1);
        }
        strcpy(tpinfo->dompwd, "xamt123");

        if (tpstart((TPSTART_T *)tpinfo) == -1){
            printf("tpstart fail tperrno = %d\n", tperrno);
            exit(1);
        }

        if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = fbput(sndbuf, TIP_OPERATION, "GET", 0);
        n = fbput(sndbuf, TIP_SEGMENT, "STATISTICS", 0);
        switch (sect) {
            case SEC_NODE:
                n = fbput(sndbuf, TIP_SECTION, "NODE", 0);
                break;
            case SEC_TPROC:
                n = fbput(sndbuf, TIP_SECTION, "TPROC", 0);
                break;
            case SEC_SPR:
                n = fbput(sndbuf, TIP_SECTION, "SPR", 0);
                break;
            case SEC_SERVICE:
                n = fbput(sndbuf, TIP_SECTION, "SERVICE", 0);
                break;
            case SEC_RQ:
                n = fbput(sndbuf, TIP_SECTION, "RQ", 0);
                break;
            case SEC_TMS:
                stat = 1;
                n = fbput(sndbuf, TIP_SECTION, "TMS", 0);
                n = fbput(sndbuf, TIP_EXTRA_OPTION, (char *)&stat, 0);
                break;
            case SEC_TMMS:
                n = fbput(sndbuf, TIP_SECTION, "TMMS", 0);
                break;
            case SEC_CLHS:
                n = fbput(sndbuf, TIP_SECTION, "CLHS", 0);
                break;
            case SEC_SERVER:
                n = fbput(sndbuf, TIP_SECTION, "SERVER", 0);
                break;
        }
        n = fbput(sndbuf, TIP_NODENAME, nodename, 0);

        n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf,
                    &rcvlen, TPNOFLAGS);
        if (n < 0) {
            printf("tpcall fail [%s]\n", tpstrerror(tperrno));
            fbprint(rcvbuf);
            tpfree((char *)sndbuf);
            tpfree((char *)rcvbuf);
            tpend();
            exit(1);
        }

        fbprint(rcvbuf);

        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}

[Result]

The following is the result (TMS STATISTICS) of the previous program:

$  client 3000 1 2
fkey = 217326601, fname = TIP_ERROR, type = int, value = 0
fkey = 485762680, fname = TIP_TMS_NAME, type = string, value = tms_ora2
fkey = 485762681, fname = TIP_SVG_NAME, type = string, value = xa1
fkey = 217327226, fname = TIP_SPRI, type = int, value = 0
fkey = 485762649, fname = TIP_STATUS, type = string, value = RUN
fkey = 217327197, fname = TIP_COUNT, type = int, value = 0
fkey = 351544938, fname = TIP_AVERAGE, type = float, value = 0.000000
fkey = 217327212, fname = TIP_CQCOUNT, type = int, value = 0
fkey = 217327227, fname = TIP_TI_THRI, type = int, value = 1
fkey = 351544956, fname = TIP_TI_AVG, type = float, value = 0.000000
fkey = 485762685, fname = TIP_TI_XID, type = string, value = 00000013664
fkey = 485762686, fname = TIP_TI_XA_STATUS, type = string, value = COMMIT

5.6. Program for Starting and Terminating a Server Process

Example 1

The following is an example of a program that starts and terminates a server process:

< cli.c >

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/fbuf.h>
#include <usrinc/tmaxapi.h>
#include <usrinc/tip.h>

#define NODE_NAME_SIZE  32

main(int argc, char *argv[])
{
        FBUF    *sndbuf, *rcvbuf;
        TPSTART_T *tpinfo;
        int   i, n, type, clid, count, flags;
        long  rcvlen;
        char  svrname[TMAX_NAME_SIZE];
        char  svgname[TMAX_NAME_SIZE];
        char  nodename[NODE_NAME_SIZE];
        int   pid, forkcnt;

        if (argc != 6) {
            printf("Usage: %s type svrname count nodename forkcnt\n", argv[0]);
            printf("type 1: BOOT, 2: DOWN, 3: DISCON\n");
            exit(1);
        }

        type = atoi(argv[1]);
        if ((type != 1) && (type != 2) && (type != 3)) {
            printf("couldn't support such a type %d\n", type);
            exit(1);
        }

        if (strlen(argv[2]) >= TMAX_NAME_SIZE) {
            printf("too large name [%s]\n", argv[1]);
            exit(1);
        }
        strcpy(svrname, argv[2]);
        count = atoi(argv[3]);
        flags = 0;

        strncpy(nodename, argv[4], NODE_NAME_SIZE - 1);
        forkcnt = atoi(argv[5]);

        n = tmaxreadenv("tmax.env", "TMAX");
        if (n < 0) {
           fprintf(stderr, "can't read env\n");
           exit(1);
        }

        tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0);
        if (tpinfo == NULL) {
            printf("tpalloc fail tperrno = %d\n", tperrno);
            exit(1);
        }
        strcpy(tpinfo->usrname, ".tpadmin");

        for (i = 1; i < forkcnt; i++) {
            if ((pid = fork()) < 0)
                exit(1);
            else if (pid == 0)
                break;
        }

        if (tpstart((TPSTART_T *)tpinfo) == -1){
            printf("tpstart fail tperrno = %d\n", tperrno);
            exit(1);
        }

        if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        n = fbput(sndbuf, TIP_OPERATION, "GET", 0);
        n = fbput(sndbuf, TIP_SEGMENT, "ADMINISTRATION", 0);
        if (type == 1)
            n = fbput(sndbuf, TIP_CMD, "BOOT", 0);
        else if (type == 2)
            n = fbput(sndbuf, TIP_CMD, "DOWN", 0);
        else
            n = fbput(sndbuf, TIP_CMD, "DISCON", 0);

        if (type == 3) {
            clid = count;       /* at type 3 */
            flags |= TIP_SFLAG;
            n = fbput(sndbuf, TIP_CLID, (char *)&clid, 0);
            n = fbput(sndbuf, TIP_FLAGS, (char *)&flags, 0);
        } else {
            flags |= TIP_SFLAG;
            n = fbput(sndbuf, TIP_SVRNAME, svrname, 0);
            n = fbput(sndbuf, TIP_COUNT, (char *)&count, 0);
            n = fbput(sndbuf, TIP_FLAGS, (char *)&flags, 0);
        }

        n = fbput(sndbuf, TIP_NODENAME, nodename, 0);

        n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf,
                    &rcvlen, TPNOFLAGS);
        if (n < 0) {
            printf("tpcall failed! errno = %d[%s]\n", tperrno, tpstrerror(tperrno));
            fbprint(rcvbuf);
            tpfree((char *)sndbuf);
            tpfree((char *)rcvbuf);
            tpend();
            exit(1);
        }

        fbprint(rcvbuf);

        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
Example 2

The following is an example of a program that changes the log level of a server named 'svr23_stat_ins' to debug4:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <usrinc/atmi.h>
#include <usrinc/fbuf.h>
#include <usrinc/tmaxapi.h>
#include <usrinc/tip.h>
#include "../fdl/tip_fdl.h"

#define NFLAG 32
#define GFLAG 8
#define VFLAG 1024

int case_chlog(int, char *[], FBUF *);

#define NODE_NAME_SIZE  32

main(int argc, char *argv[])
{
      FBUF    *sndbuf, *rcvbuf;
      TPSTART_T *tpinfo;
      int   i, ret, n, type, clid, count, flags = 0;
      long  rcvlen;
      char  svrname[TMAX_NAME_SIZE];
      char  svgname[TMAX_NAME_SIZE];
      char  nodename[NODE_NAME_SIZE];
      int   pid, forkcnt;

      if (argc < 6) {
          printf("Usage: %s svgname svrname nodename  [chlogmodule] [flags]
                                                      [loglvl]\n", argv[0]);
          printf("chlogmodule 1: TIP_TMM, 2: TIP_CLH, 4: TIP_TMS, 8: TIP_SVR\n");
          printf("flags 1: NFLAGS, 2: GFLAGS, 3: VFLAGS\n");
          printf("loglvl : 1: compact, 2: basic, 3: detail, 4: debug1, 5: debug2,
                           6: debug3, 7: debug4\n");
          exit(1);
      }

      n = tmaxreadenv("tmax.env", "TMAX");
      if (n < 0) {
          fprintf(stderr, "can't read env\n");
          exit(1);
       }

       tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0);
       if (tpinfo == NULL) {
           printf("tpalloc fail tperrno = %d\n", tperrno);
           exit(1);
        }
        strcpy(tpinfo->usrname, ".tpadmin");
        strcpy(svgname, argv[1]);
        strcpy(svrname, argv[2]);
        strncpy(nodename, argv[3], NODE_NAME_SIZE - 1);

        if (tpstart((TPSTART_T *)tpinfo) == -1){
            printf("tpstart fail tperrno = %d\n", tperrno);
            exit(1);
        }

        if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
            tpend();
            exit(1);
        }

        ret = case_chlog(argc, argv, sndbuf);
        n = fbput(sndbuf, TIP_OPERATION, "GET", 0);
        n = fbput(sndbuf, TIP_SEGMENT, "ADMINISTRATION", 0);
        n = fbput(sndbuf, TIP_CMD, "CHLOG", 0);
        n = fbput(sndbuf, TIP_NODENAME, nodename, 0);
        n = fbput(sndbuf, TIP_SVGNAME, svgname , 0);
        n = fbput(sndbuf, TIP_SVRNAME, svrname, 0);

        n=tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf, &rcvlen, TPNOFLAGS);
        if (n < 0) {
             printf("tpcall failed! errno = %d[%s]\n", tperrno, tpstrerror(tperrno));
             fbprint(rcvbuf);
             tpfree((char *)sndbuf);
             tpfree((char *)rcvbuf);
             tpend();
             exit(1);
        }

        fbprint(rcvbuf);
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}

int case_chlog(int argc2, char *argv2[], FBUF *sndbuf)
{
        int  chlogmdl, loglvl, flags, n=0;
        char  cloglvl[TMAX_NAME_SIZE];
        const int true = 1, false = 0;

        chlogmdl = atoi(argv2[4]);
        if( (chlogmdl != 1) && (chlogmdl != 2) && (chlogmdl != 4) &&
            (chlogmdl != 8) {
                printf("couldn't support such a chlogmdl\n");
                exit(1);
        }

        flags = atoi(argv2[5]);
        if( (flags != NFLAG) && (flags != GFLAG) && (flags != VFLAG) ) {
                printf("couldn't support such a flags\n");
                exit(1);
        }

        loglvl = atoi(argv2[6]);
        if( (loglvl < 1) || (loglvl > 7) ) {
                printf("couldn't support such a loglvl\n");
                exit(1);
        }

        switch (loglvl)
        {
                case 1 :
                        strcpy(cloglvl, "compact");
                        break;
                case 2 :
                        strcpy(cloglvl, "basic");
                        break;
                case 3 :
                        strcpy(cloglvl, "detail");
                        break;
                case 4 :
                        strcpy(cloglvl, "debug1");
                        break;
                case 5 :
                        strcpy(cloglvl, "debug2");
                        break;
                case 6 :
                        strcpy(cloglvl, "debug3");
                        break;
                case 7 :
                        strcpy(cloglvl, "debug4");
                        break;
        }
        n = fbput(sndbuf, TIP_MODULE, (char *)&chlogmdl, 0);
        n = fbput(sndbuf, TIP_FLAGS, (char *)&flags , 0);
        n = fbput(sndbuf, TIP_LOGLVL, cloglvl , 0);
        return 1;
}

[Result] (TIP_SVR => DEBUG4)

$ client  xa1 svr23_stat_ins $HOSTNAME 8 1024 7
fkey = 217326601, fname = TIP_ERROR, type = int, value = 0
>>> tmadmin (cfg -v)

         loglvl = DEBUG4

6. Local recursive call

When tpcall() is executed in a server, the recursive service call feature is added. Only tpcall() can make recursive calls through the multicontext technique in a server. The recursion depth is limited to 8 to prevent an infinite loop.

To use a local recursive call, –D_MCONTEXT must be added to CFLAGS when a server program is compiled and the libsvrmc.so server library must be used instead of libsvr.so.

Server Program

The following is an example of a server program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <usrinc/atmi.h>


SVC15004_1(TPSVCINFO *msg)
{
         int     i;
         char    *rcvbuf;
         long    rcvlen;

         if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL)
              printf("rcvbuf tpalloc fail[%s]\n",tpstrerror(tperrno));
         if (tpcall("SVC15004_2", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1) {
              printf("tpcall fail [%s]\n", tpstrerror(tperrno));
              tpfree((char *)rcvbuf);
              tpreturn(TPFAIL, 0, 0, 0, 0);
         }

         strcat(rcvbuf, "_Success");
         tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0);
}

SVC15004_2(TPSVCINFO *msg)
{
         int     i;
         char    *rcvbuf;
         long    rcvlen;

         if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL)
             printf("rcvbuf tpalloc fail \n");
}

         if (tpcall("SVC15004_3", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1)
         {
             printf("tpcall fail [%s]\n", tpstrerror(tperrno));
             tpfree((char *)rcvbuf);
             tpreturn(TPFAIL, 0, 0, 0, 0);
         }
         strcat(rcvbuf, "_Success");
         tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0);
}

SVC15004_3(TPSVCINFO *msg)
{
         int     i;
         char    *rcvbuf;
         long    rcvlen;

         if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL)
              printf("rcvbuf tpalloc fail \n");

         if (tpcall("SVC15004_4", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1)
         {
             printf("tpcall fail [%s]\n", tpstrerror(tperrno));
             tpfree((char *)rcvbuf);
             tpreturn(TPFAIL, 0, 0, 0, 0);
          }

         strcat(rcvbuf, "_Success");
         tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0);
}
Makefile

The following is an example of a makefile:

<Makefile.c.mc>

# Server makefile

TARGET  = $(COMP_TARGET)
APOBJS  = $(TARGET).o
NSDLOBJ = $(TMAXDIR)/lib64/sdl.o

LIBS    = -lsvrmc -lnodb
OBJS    = $(APOBJS) $(SVCTOBJ)

SVCTOBJ = $(TARGET)_svctab.o

CFLAGS  = -O -Ae -w +DSblended +DD64 -D_HP -I$(TMAXDIR) -D_MCONTEXT

APPDIR  = $(TMAXDIR)/appbin
SVCTDIR = $(TMAXDIR)/svct
LIBDIR  = $(TMAXDIR)/lib64

#
.SUFFIXES : .c

.c.o:
        $(CC) $(CFLAGS) -c $<

#
# server compile
#

$(TARGET): $(OBJS)
        $(CC) $(CFLAGS) -L$(LIBDIR) -o $(TARGET) $(OBJS) $(LIBS) $(NSDLOBJ)
        mv $(TARGET) $(APPDIR)/.
        rm -f $(OBJS)

$(APOBJS): $(TARGET).c
        $(CC) $(CFLAGS) -c $(TARGET).c

$(SVCTOBJ):
        cp -f $(SVCTDIR)/$(TARGET)_svctab.c .
        touch ./$(TARGET)_svctab.c
        $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c

#
clean:
        -rm -f *.o core $(APPDIR)/$(TARGET)