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.

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:
|
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.
-
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: …
-
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:
-
Whether the DB2 client engine is 32bit or 64bit.
-
Whether the version of the DB2 client is 8.0 or earlier, or 9.0 or later.
-
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
-
-
-
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:
-
Whether the DB2 client engine is 32bit or 64bit.
-
Whether the version of the DB2 client is 8.0 or earlier, or 9.0 or later.
-
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
-
-
-
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.

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.

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.

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.

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)