MultipleRM Program Examples
This chapter describes examples of MultipleRM programs, environment configuration, and makefiles for compilation in TCS.
1. Using Oracle and Tibero
In TCS, Oracle and Tibero can be used through the server library. This section describes examples of MultipleRM programs, environment configuration, and makefile for compilation.
1.1. Program Examples
The following shows sample TCS programs that use both Oracle and Tibero. The program examples can be used by writing a server program with Embedded SQL and pre-compiling it with the pre-compiler provided by each database vendor.
Service Execution
The following is program source code that executes a service.
#include <stdio.h> #include <usrinc/atmi.h> extern int oracle_call(TPSVCINFO *msg); extern int tibero_call(TPSVCINFO *msg); MDB_SVC1(TPSVCINFO *msg) { int ret; int fail = 0; ret = oracle_call(msg); if (ret < 0) { fail = 1; } ret = tibero_call(msg); if (ret < 0) { fail = 1; } if ( fail ) { tpreturn(TPFAIL,0,(char *)msg->data, msg->len,0); } tpreturn(TPSUCCESS,0,(char *)msg->data, msg->len,0); }
Oracle Call Function
The following program uses a function to call Oracle.
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> EXEC SQL include sqlca.h; EXEC SQL begin declare section; char h_addr[100]; EXEC SQL end declare section; int oracle_call(TPSVCINFO *msg) { int i; strcpy(h_addr, msg->data); EXEC SQL INSERT INTO account( account_id, address, phone ) VALUES ( tmax_seq.nextval,:h_addr, '007-1234' ); if ( sqlca.sqlcode != 0 ){ printf( "insert failed sqlcode = %d\n",sqlca.sqlcode ); tpreturn( TPFAIL, -1, NULL, 0, 0 ); } printf("ORACLE insert Success\n"); return 0; }
Tibero Call Function
The following program uses a function to call Tibero.
#include <stdio.h> #include <string.h> #include <usrinc/atmi.h> EXEC SQL include sqlca.h; EXEC SQL begin declare section; char h_addr[100]; EXEC SQL end declare section; int tibero_call(TPSVCINFO *msg) { strcpy(h_addr, msg->data); EXEC SQL INSERT INTO account( account_id, address, phone ) VALUES ( tmax_seq.nextval,:h_addr, '007-1234' ); if ( sqlca.sqlcode != 0 ){ printf( "tibero insert failed sqlcode = %d\n",sqlca.sqlcode ); tpreturn( TPFAIL, -1, NULL, 0, 0 ); } printf("TIBERO insert Success\n"); return 0; }
1.2. Environment Configuration
The following shows the environment configuration of MultipleRM that uses both Oracle and Tibero.
*DOMAIN domain SHMKEY = 81522, MAXUSER = 10000, MINCLH = 1, MAXCLH = 1, TPORTNO = 11500, BLOCKTIME = 30, MAXSACALL = 1024, MAXCACALL = 1024, MAXMTMAX = 3, MAXSTMAX = 10 *NODE node1 TMAXDIR = "/home/tmax", APPDIR = "/home/tmax/appbin", PATHDIR = "/home/tmax/path", TLOGDIR = "/home/tmax/log/tlog", ULOGDIR = "/home/tmax/log/ulog", SLOGDIR = "/home/tmax/log/slog" *SVRGROUP svg_s1 NODENAME = node1, DBNAME = ORACLE, OPENINFO ="Oracle_Xa+SqlNet=TMAX+Acc=P/scott/tiger+SesTm=60", TMSNAME = tms_ora, SVGTYPE = STMAX svg_s2 NODENAME = node1, DBNAME = TIBERO, OPENINFO ="TIBERO_XA:user=scott,pwd=tiger, sestm=60,db=TMAX", TMSNAME = tms_tbr, SVGTYPE = STMAX
1.3. Compilation
This section describes an example of compiling MultipleRM using Oracle and Tibero.
When building a program, if a library (e.g. liboras.so) that defines the _tmax_xasw_init() function is linked, follow the process of Extracting a library list in RM File. Otherwise, follow the process of Using definitions in the configuration file. -lnodb must be included in the LIBS (Tmax library) item of the makefile.
Makefile contents may vary depending on the operating system. |
The following is a makefile that compiles a MultipleRM server program on 32-bit Linux.
# Oracle Env ORALIBDIR = /home/OraHome1/lib/ ORALIB = -lclntshcat /home/OraHome1/lib/ldflags
cat /home/OraHome1/lib/sysliblist
-ldl -lm # Tibero Env TBRLIB = -ltbxa -ltbertl TBRLIBDIR = $(TB_HOME)/client/lib TBRINCDIR = $(TB_HOME)/client/include $ Server build TARGET = $(COMP_TARGET) APOBJS = $(TARGET).o AP_ORA_OBJS = $(TARGET)_ora.o AP_TBR_OBJS = $(TARGET)_tbr.o NSDLOBJ = $(TMAXDIR)/lib/sdl.o LIBS = -lnsl -lsvr -lnodb OBJS = $(AP_ORA_OBJS) $(AP_TBR_OBJS) $(SVCTOBJ) $(APOBJS) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -I$(TMAXDIR) APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib # .SUFFIXES : .c .c.o: echo $(OBJS) $(CC) $(CFLAGS) -c $< # # server compile # all: $(TARGET) $(TARGET):$(OBJS) echo $(OBJS) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(TBRLIBDIR) -L$(ORALIBDIR) $(ORALIB) $(TBRLIB) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(AP_ORA_OBJS): echo $(OBJS) proc iname=$(TARGET)_ora.pc include=$(TMAXDIR) $(CC) $(CFLAGS) -c $(TARGET)_ora.c $(AP_TBR_OBJS): echo $(OBJS) tbpc iname=$(TARGET)_tbr.tbc include=$(TMAXDIR) $(CC) $(CFLAGS) -I$(TBRINCDIR) -c $(TARGET)_tbr.c $(APOBJS): echo $(OBJS) $(CC) $(CFLAGS) -c $(TARGET).c $(SVCTOBJ): echo $(OBJS) cp -f $(SVCTDIR)/$(TARGET)_svctab.c . touch ./$(TARGET)_svctab.c $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c # clean: -rm -f *.o core $(TARGET) $(TARGET).lis
2. Using Two Oracle Instances
Two Oracle instances can be used in TCS through the server library. This section describes examples of programs that use two Oracle instances, environment configuration, and makefile for compilation.
2.1. Program Examples
The following example shows transaction processing on a single server that uses two Oracle RM instances.
Since the same Oracle client library is used, the user must specify the instance to use when executing a query from user code. For xa_open in Oracle, an OCI function, such as xaoSvcCtx or xaoEnv, can be used to obtain a connection to the desired instance.
Service Execution
The following is program source code that executes a service.
#include <stdio.h> #include <usrinc/atmi.h> extern int oracle_call(TPSVCINFO *msg); MDB_SVC2(TPSVCINFO *msg) { int ret; int fail = 0; ret = oracle_call(msg); if (ret < 0) { fail = 1; } if ( fail ) { tpreturn(TPFAIL,0,(char *)msg->data, msg->len,0); } tpreturn(TPSUCCESS,0,(char *)msg->data, msg->len,0); }
Oracle Call Function
The following program uses a function to call Oracle.
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include <oci.h> static void checkerr(errhp, status) OCIError *errhp; sword status; { text errbuf[512]; sb4 errcode; switch (status) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: break; case OCI_NEED_DATA: break; case OCI_NO_DATA: break; case OCI_ERROR: /* get the error back and display on the screen */ (void) OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR); (void) printf("Error - %s\n", errbuf); break; case OCI_INVALID_HANDLE: break; case OCI_STILL_EXECUTING: break; case OCI_CONTINUE: break; default: break; } } int oracle_call(TPSVCINFO *msg) { int i; OCIEnv *envhp; OCIServer *srvhp; OCIError *errhp; OCISvcCtx *svchp; OCISession *usrhp; OCIStmt *stmthp; dvoid *tmp; char *sql = {"INSERT " "INTO hahehiho_account( account_id, address, phone ) " "VALUES ( skt_seq.nextval,'asdf', '007-1234' )"}; char *sql2 = {"INSERT " "INTO hahehiho_account( account_id, address, phone ) " "VALUES ( skt_seq.nextval,'fdsa', '700-1234' )"}; svchp = xaoSvcCtx("A"); envhp = xaoEnv("A"); printf("oracle call A octxt[%d]\n", svchp); OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp); checkerr(errhp, OCIStmtPrepare(stmthp, errhp,(text *)sql, (ub4)strlen(sql), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); svchp = xaoSvcCtx("B"); envhp = xaoEnv("B"); printf("oracle call B octxt[%d]\n", svchp); OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) &tmp); OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, (ub4) OCI_HTYPE_STMT, 50, (dvoid **) &tmp); checkerr(errhp, OCIStmtPrepare(stmthp, errhp,(text *)sql2, (ub4)strlen(sql2), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT)); return 0; }
2.2. Environment Configuration and Compilation
The following shows the environment configuration and compilation of MultipleRM that uses two Oracle instances.
Environment Configuration
The following is a MultipleRM server configuration example.
*DOMAIN domain SHMKEY = 81522, MAXUSER = 10000, MINCLH = 1, MAXCLH = 1, TPORTNO = 11500, BLOCKTIME = 30, MAXSACALL = 1024, MAXCACALL = 1024, MAXMTMAX = 3, MAXSTMAX = 10 *NODE node1 TMAXDIR = "/home/tmax", APPDIR = "/home/tmax/appbin", PATHDIR = "/home/tmax/path", TLOGDIR = "/home/tmax/log/tlog", ULOGDIR = "/home/tmax/log/ulog", SLOGDIR = "/home/tmax/log/slog" *SVRGROUP svg_s1 NODENAME = node1, DBNAME = ORACLE, OPENINFO ="Oracle_Xa+SqlNet=TMAX1+Acc=P/scott/tiger+SesTm=60+DB=A", TMSNAME = tms_ora, SVGTYPE = STMAX, RMID = 0 svg_s2 NODENAME = node1, DBNAME = ORACLE, OPENINFO ="Oracle_Xa+SqlNet=TMAX2+Acc=P/scott/tiger+SesTm=60+DB=B", TMSNAME = tms_ora, SVGTYPE = STMAX, RMID = 1 svgm1 NODENAME = node1, SVGLIST = "svg_s2,svg_s1", SVGTYPE = MTMAX *SERVER sample SVGNAME = svgm1, LOGLVL = DEBUG4 *SERVICE MDB_SVC2 SVRNAME = sample
Makefile
-lnodb must be included in the LIBS item of the makefile. The following is a makefile example that compiles a MultipleRM server program on 32-bit Linux.
# Oracle Env ORALIBDIR = /home/OraHome1/lib/ ORALIB = -lclntshcat /home/OraHome1/lib/ldflags
cat /home/OraHome1/lib/sysliblist
-ldl -lm LIBS = -lnsl -lsvrmrm OBJS = $(AP_ORA_OBJS) $(AP_TBR_OBJS) $(SVCTOBJ) $(APOBJS) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -I$(TMAXDIR) APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svctTARGET = $(COMP_TARGET) APOBJS = $(TARGET).o AP_ORA_OBJS = $(TARGET)_ora.o NSDLOBJ = $(TMAXDIR)/lib/sdl.o LIBS = -lnsl -lsvr -lnodb OBJS = $(AP_ORA_OBJS) $(SVCTOBJ) $(APOBJS) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -I$(TMAXDIR) -I$(ORACLE_HOME)/include -I$(ORACLE_HOME)/rdbms/demo -I$(ORACLE_HOME)/rdbms/public APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib # .SUFFIXES : .c .c.o: echo $(OBJS) $(CC) $(CFLAGS) -c $< # # server compile # all: $(TARGET) $(TARGET):$(OBJS) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(ORALIBDIR) $(ORALIB) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(AP_ORA_OBJS): $(CC) $(CFLAGS) -c $(TARGET)_ora.c $(APOBJS): $(CC) $(CFLAGS) -c $(TARGET).c $(SVCTOBJ): echo $(OBJS) cp -f $(SVCTDIR)/$(TARGET)_svctab.c . touch ./$(TARGET)_svctab.c $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c # clean: -rm -f *.o core $(TARGET) $(TARGET).lis
Makefile contents may vary depending on the operating system. |
3. Using Oracle and DB2
Oracle and DB2 can be used in TCS using the server library. This section provides examples of programs that use Oracle and DB2, as well as examples of makefiles for configuration and compilation.
3.1. Program Examples
The following is a TCS example program that uses Oracle and DB2 together. This program example can be written using embedded SQL and compiled using a precompiler provided by each database vendor.
Service Execution
The following is program source code that executes a service.
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> extern int SVC2301TX_1_oracle(TPSVCINFO *msg); extern int SVC2301TX_1_db2(TPSVCINFO *msg); extern int SVC2301TX_2_oracle(TPSVCINFO *msg); extern int SVC2301TX_2_db2(TPSVCINFO *msg); extern int SVC2301TX_3_oracle(TPSVCINFO *msg); extern int SVC2301TX_3_db2(TPSVCINFO *msg); extern int SVC2301TX_4_oracle(TPSVCINFO *msg); extern int SVC2301TX_4_db2(TPSVCINFO *msg); SVC2301TX_1( TPSVCINFO *msg ) { int ret; int fail = 0; char *rcvbuf; rcvbuf=(char *)tpalloc("STRING", NULL, 4096); if(rcvbuf==NULL) { printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, -1, NULL, 0, 0); } ret = SVC2301TX_1_oracle(msg); if (ret < 0) { fail = 1; } ret = SVC2301TX_1_db2(msg); if (ret < 0) { fail = 1; } if ( fail ) { printf("SVC2301TX_1 FAIL\n"); tpreturn(TPFAIL,-1,NULL, 0,0); } strcpy(rcvbuf, "Multiple RM Insert Success"); tpreturn( TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0 ); } SVC2301TX_2( TPSVCINFO *msg ) { int ret; int fail = 0; char *rcvbuf; rcvbuf=(char *)tpalloc("STRING", NULL, 4096); if(rcvbuf==NULL) { printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, -1, NULL, 0, 0); } ret = SVC2301TX_2_oracle(msg); if (ret < 0) { fail = 1; } ret = SVC2301TX_2_db2(msg); if (ret < 0) { fail = 1; } if ( fail ) { printf("SVC2301TX_2 FAIL\n"); tpreturn(TPFAIL,-1,NULL, 0,0); } strcpy(rcvbuf, "Multiple RM Update Success"); tpreturn( TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0 ); } SVC2301TX_3( TPSVCINFO *msg ) { int ret; int fail = 0; char *rcvbuf; rcvbuf=(char *)tpalloc("STRING", NULL, 4096); if(rcvbuf==NULL) { printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, -1, NULL, 0, 0); } ret = SVC2301TX_3_oracle(msg); if (ret < 0) { fail = 1; } ret = SVC2301TX_3_db2(msg); if (ret < 0) { fail = 1; } if ( fail ) { printf("SVC2301TX_3 FAIL\n"); tpreturn(TPFAIL,-1,NULL, 0,0); } strcpy(rcvbuf, "Multiple RM Delete Success"); tpreturn( TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0 ); } SVC2301TX_4( TPSVCINFO *msg ) { int ret; int fail = 0; char *rcvbuf; rcvbuf=(char *)tpalloc("STRING", NULL, 4096); if(rcvbuf==NULL) { printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, -1, NULL, 0, 0); } ret = SVC2301TX_4_oracle(msg); if (ret < 0) { fail = 1; } ret = SVC2301TX_4_db2(msg); if (ret < 0) { fail = 1; } if ( fail ) { printf("SVC2301TX_4 FAIL\n"); tpreturn(TPFAIL,-1,NULL, 0,0); } strcpy(rcvbuf, "Multiple RM Select Success"); tpreturn( TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0 ); }
Oracle Call Function
The following program uses a function to call Oracle.
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> EXEC SQL INCLUDE SQLCA.H; EXEC SQL BEGIN DECLARE SECTION; int h_empno; char h_ename[MAXLEN]; char h_job[MAXLEN]; char h_date[MAXLEN]; float h_sal; int h_count; char h_xid[100]; EXEC SQL END DECLARE SECTION; SVC2301TX_1_oracle( TPSVCINFO *msg ) { str sndbuf; char *rcvbuf; char tmp[1024]; TXINFO info; 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); memset( h_xid , 0x00, sizeof( h_xid ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); if (tx_info(&info)==1) { sprintf(h_xid, "%x %x %x %x - %x %x %x %x", (unsigned char)info.xid.data[0], (unsigned char)info.xid.data[1], (unsigned char)info.xid.data[2], (unsigned char)info.xid.data[3], (unsigned char)info.xid.data[4], (unsigned char)info.xid.data[5], (unsigned char)info.xid.data[6], (unsigned char)info.xid.data[7]); printf("xid=[%s] \n", h_xid); } else { printf("Not in transaction \n"); tpreturn(TPFAIL, -1, NULL, 0, 0); } EXEC SQL INSERT INTO tmax( empno, ename, job, hiredate,sal, xid) VALUES (:h_empno, :h_ename, :h_job, to_date(:h_date,'yymmdd'), :h_sal, :h_xid ); if ( sqlca.sqlcode != SQLOK ) { sprintf(tmp, "[%s] ORACLE tmax Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] ORACLE tmax Insert Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_2_oracle( TPSVCINFO *msg ) { 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL UPDATE tmax SET empno = :h_empno+1, ename = :h_ename, job = 'UPDATE' WHERE empno = :h_empno; if ( sqlca.sqlcode != SQLOK ) { sprintf(tmp, "[%s] ORACLE tmax Update Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] ORACLE tmax Update Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_3_oracle( TPSVCINFO *msg ) { 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL DELETE tmax WHERE empno = :h_empno; if ( sqlca.sqlcode != SQLOK ) { sprintf(tmp, "[%s] ORACLE tmax Delete Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] ORACLE tmax Delete Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_4_oracle( TPSVCINFO *msg ) { 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); } h_empno = h_sal = h_count = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL SELECT COUNT(*) INTO :h_count FROM tmax WHERE empno = :h_empno; if ((sqlca.sqlcode != SQLOK) && (sqlca.sqlcode != SQLNOTFOUND)) { sprintf(tmp, "[%s] ORACLE tmax Select Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] ORACLE tmax Select Success [%d]", msg->name, h_count); strcpy(rcvbuf, tmp); return 0; }
DB2 Call Function
The following program uses a function to call DB2.
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include "svr1.h" EXEC SQL INCLUDE SQLCA; EXEC SQL BEGIN DECLARE SECTION; sqlint32 h_empno; char h_ename[50]; char h_job[50]; char h_date[50]; float h_sal; sqlint32 h_count; char h_xid[100]; EXEC SQL END DECLARE SECTION; SVC2301TX_1_db2( TPSVCINFO *msg ) { str sndbuf; char *rcvbuf; char tmp[1024]; TXINFO info; 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); memset( h_xid , 0x00, sizeof( h_xid ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); if (tx_info(&info)==1) { sprintf(h_xid, "%x %x %x %x - %x %x %x %x", (unsigned char)info.xid.data[0], (unsigned char)info.xid.data[1], (unsigned char)info.xid.data[2], (unsigned char)info.xid.data[3], (unsigned char)info.xid.data[4], (unsigned char)info.xid.data[5], (unsigned char)info.xid.data[6], (unsigned char)info.xid.data[7]); printf("xid=[%s] \n", h_xid); } else { printf("Not in transaction \n"); tpreturn(TPFAIL, -1, NULL, 0, 0); } EXEC SQL INSERT INTO tmax( empno, ename, job, hiredate,sal, xid) VALUES (:h_empno, :h_ename, :h_job, to_date(:h_date,'yymmdd'), :h_sal, :h_xid ); if (sqlca.sqlcode != SQLOK) { sprintf(tmp, "[%s] DB2 tmax Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] DB2 tmax Insert Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_2_db2( TPSVCINFO *msg ) { 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL UPDATE tmax SET empno = :h_empno+1, ename = :h_ename, job = 'UPDATE' WHERE empno = :h_empno; if (sqlca.sqlcode != SQLOK) { sprintf(tmp, "[%s] DB2 tmax Update Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] DB2 tmax Update Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_3_db2( TPSVCINFO *msg ) { 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL DELETE tmax WHERE empno = :h_empno; if (sqlca.sqlcode != SQLOK) { sprintf(tmp, "[%s] DB2 tmax Delete Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] DB2 tmax Delete Success", msg->name); strcpy(rcvbuf, tmp); return 0; } SVC2301TX_4_db2( TPSVCINFO *msg ) { 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); } h_empno = h_sal = h_count = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); EXEC SQL SELECT COUNT(*) INTO :h_count FROM tmax WHERE empno = :h_empno; if ((sqlca.sqlcode != SQLOK) && (sqlca.sqlcode != SQLNOTFOUND)) { sprintf(tmp, "[%s] DB2 tmax Select Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] DB2 tmax Select Success [%d]", msg->name, h_count); strcpy(rcvbuf, tmp); return 0; }
Since MultipleRM does not support xa dynamic registration, tx_begin() must always be called even when executing a SELECT statement for business purposes. Alternatively, the service handling the SELECT statement must be separated into a dedicated server that does not include services performing INSERT, UPDATE, or DELETE operations to ensure proper operation. |
3.2. Environment Configuration and Compilation
The following shows the environment configuration and compilation of MultipleRM that uses Oracle and DB2.
Environment Configuration
The following is a MultipleRM server configuration example.
*DOMAIN dom1 SHMKEY =@SHMEMKY@, MINCLH=1, MAXCLH=1, TPORTNO=@TPORTNO@, BLOCKTIME=60, RACPORT = @TRACPORT@, MAXTMS=50 *NODE @HOSTNAME@ TMAXDIR="@TMAXDIR@", APPDIR="@TMAXDIR@/appbin", PATHDIR = "@TMAXDIR@/path", TLOGDIR = "@TMAXDIR@/log/tlog", ULOGDIR="@TMAXDIR@/log/ulog", SLOGDIR="@TMAXDIR@/log/slog", *SVRGROUP svg12301X NODENAME = @HOSTNAME@, DBNAME = ORACLE, OPENINFO="Oracle_Xa+Acc=P/scott/tiger+SesTm=60+DbgFl=7+LogDir=@TMAXDIR@/log/xalog", TMSNAME = tms_ora, SVGTYPE = STMAX svg12302X NODENAME = @HOSTNAME@, DBNAME = DB2_STATIC, OPENINFO = "db=tptest,uid=tmaxha,pwd=ha0115", TMSNAME = tms_db2, SVGTYPE = STMAX svgm1 NODENAME = @HOSTNAME@, SVGLIST = "svg12301X, svg12302X", SVGTYPE = MTMAX *SERVER # Common Insert/Update/Delete/Select svr2301TX SVGNAME = svgm1, MIN=5, MAX=5, MAXRSTART=-1 svr2301TX_UCS SVGNAME = svgm1, MIN=5, MAX=5, MAXRSTART=-1, SVRTYPE=UCS # Server Transaction svr2311TX SVGNAME = svg12301X # tpforward svr2321TX SVGNAME = svg12301X svr2322TX SVGNAME = svg12301X # AUTOTRAN svr2331TX SVGNAME = svg12301X *SERVICE # Common Insert/Update/Delete/Select SVC2301TX_1 SVRNAME = svr2301TX, SVCTIME=5 SVC2301TX_2 SVRNAME = svr2301TX, SVCTIME=5 SVC2301TX_3 SVRNAME = svr2301TX, SVCTIME=5 SVC2301TX_4 SVRNAME = svr2301TX, SVCTIME=5 SVC2301TX_1_UCS SVRNAME = svr2301TX_UCS, SVCTIME=5 SVC2301TX_2_UCS SVRNAME = svr2301TX_UCS, SVCTIME=5 SVC2301TX_3_UCS SVRNAME = svr2301TX_UCS, SVCTIME=5 SVC2301TX_4_UCS SVRNAME = svr2301TX_UCS, SVCTIME=5
Makefile
-lnodb must be included in the LIBS item of the makefile. The following is a makefile that compiles a MultipleRM server program on 64-bit Linux.
# Oracle Env include $(ORACLE_HOME)/precomp/lib/env_precomp.mk ORALIBDIR = $(LIBHOME) ORALIB = $(PROLDLIBS) # DB2 Env DB2LIBDIR = $(DB2_HOME)/lib DB2LIBS = -ldb2 DB = TPTEST DB2USER = tmaxha DB2PASS = ha0115 # Server makefile TARGET = $(COMP_TARGET) APOBJS = $(TARGET).o NSDLOBJ = $(TMAXDIR)/lib64/sdl.o AP_ORA_OBJS = $(TARGET)_ora.o AP_DB2_OBJS = $(TARGET)_db2.o LIBS = -lsvr -lnsl -lnodb OBJS = $(AP_ORA_OBJS) $(AP_DB2_OBJS) $(APOBJS) $(SVCTOBJ) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -I$(TMAXDIR) APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib64 # .SUFFIXES : .c .c.o: $(CC) $(CFLAGS) -c $< # # server compile # all: $(TARGET) $(TARGET): $(OBJS) echo $(ORALIBDIR) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(DB2LIBDIR) -L$(ORALIBDIR) $(ORALIB) $(DB2LIBS) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(AP_ORA_OBJS): echo $(OBJS) proc iname=$(TARGET)_ora.pc include=$(TMAXDIR) $(CC) $(CFLAGS) -c $(TARGET)_ora.c $(AP_DB2_OBJS): echo $(OBJS) db2 connect to $(DB) user $(DB2USER) using $(DB2PASS) db2 prep $(TARGET)_db2.sqc bindfile db2 bind $(TARGET)_db2.bnd db2 connect reset db2 terminate $(CC) $(CFLAGS) $(LDFLAGS) -I$(DB2_HOME)/include -c $(TARGET)_db2.c $(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)
Makefile contents may vary depending on the operating system. |
4. Using Oracle and MQ
Oracle and MQ can be used with TCS using the server library. This section provides examples of programs that use Oracle and MQ, as well as a makefile example for configuration and compilation.
4.1. Program Examples
The following is a TCS example program that uses Oracle and MQ together. This program example can be written using embedded SQL and compiled using a precompiler provided by each database vendor.
MQ Call Function
The following program uses a function to call MQ.
#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 #define DATA_LEN 16 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 first; 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:o:OE")) != 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 'O': first = 0; break; case 'E': first = 1; 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; } INSERT_MQ(TPSVCINFO *msg) { MQMD md = {MQMD_DEFAULT}; /* Message Descriptor */ MQPMO pmo = {MQPMO_DEFAULT}; /* put message options */ MQLONG CompCode; /* completion code */ MQLONG Reason; /* reason code */ 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 */ msg->data, /* 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) tpreturn(TPSUCCESS, 0, msg->data, msg->len, 0); else tpreturn(TPFAIL, 0, msg->data, msg->len, 0); } INSERT_DB(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 = tpalloc("STRING", NULL, 50000); if (rcvbuf == NULL) tpreturn(TPFAIL, 0, 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 = 50000 -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) { msg->data = rcvbuf; msg->len = rcvlen; INSERT_ESQL(msg); tpreturn( TPSUCCESS, 0, NULL, 0, 0 ); } else { tpreturn(TPFAIL, 0, NULL, 0, 0); } }
Oracle Call Function
The following program uses a function to call Oracle.
#include <stdio.h> #include <string.h> #include <ctype.h> #include <usrinc/atmi.h> EXEC SQL include sqlca.h; EXEC SQL begin declare section; int h_empno; char h_ename[11]; char h_job[10]; int h_mgr; char h_date[11]; float h_sal; float h_comm; int h_deptno; EXEC SQL end declare section; INSERT_ESQL( TPSVCINFO *msg ) { int i; h_empno = h_mgr = h_sal = h_comm = h_deptno = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); strncpy(h_job, msg->name, 9); strncpy(h_ename, msg->data, 10); for(i = 0; i < sizeof(h_ename); i++) h_ename[i] = toupper(h_ename[i]); strcpy(h_date, "160101"); h_empno = time(NULL) % 10000; EXEC SQL DECLARE ESQL DATABASE; EXEC SQL AT ESQL INSERT INTO emp( empno, ename, job, hiredate) VALUES ( :h_empno, :h_ename, :h_job, to_date(:h_date,'yymmdd')); if (sqlca.sqlcode != 0){ printf( "insert failed sqlcode = %d\n",sqlca.sqlcode ); tpreturn( TPFAIL, -1, NULL, 0, 0 ); } printf("INSERT_ESQL insert success\n"); if (!strcmp(msg->name, "INSERT_ESQL")) tpreturn( TPSUCCESS, 0, NULL, 0, 0 ); }
4.2. Environment Configuration and Compilation
The following shows the environment configuration and compilation of MultipleRM that uses Oracle and MQ.
Environment Configuration
The following is a MultipleRM server configuration example.
*DOMAIN tmax1 SHMKEY=87789, MINCLH=1, MAXCLH=1, TPORTNO=7789, BLOCKTIME=5, TXTIME=10, RACPORT=3378, MAXCPC = 150 *NODE qpsx2 TMAXDIR = "/home/tmax2/tmax", APPDIR = "/home/tmax2/tmax/appbin", PATHDIR = "/home/tmax2/tmax/path", TLOGDIR = "/home/tmax2/tmax/log/tlog", ULOGDIR = "/home/tmax2/tmax/log/ulog", SLOGDIR = "/home/tmax2/tmax/log/slog" *SVRGROUP svg_mq NODENAME = "qpsx2", DBNAME = MQ, OPENINFO = "QMNAME=MQTEST", TMSNAME = tms_mq, SVGTYPE = STMAX, RMID = 222, MINTMS=1 svg_eora NODENAME = "qpsx2", DBNAME = ORACLE, OPENINFO = "Oracle_XA+Acc=P/scott/tiger+SesTm=60+LogDir=/home/tmax2/tmax/log/ulog+DbgFl=0x7+DB=ESQL", TMSNAME = tms_ora, SVGTYPE = STMAX, RMID = 333, MINTMS=1 svg_xa NODENAME = "qpsx2", SVGTYPE = MTMAX, SVGLIST = "svg_mq,svg_eora" *SERVER mrm_ora_mq SVGNAME = svg_xa, CLOPT = "-- -m MQTEST -q ORANGE.LOCAL.QUEUE -E", MAXRSTART = -1 *SERVICE # Common PUT/GET INSERT_DB SVRNAME = mrm_ora_mq INSERT_MQ SVRNAME = mrm_ora_mq
Makefile
-lnodb must be included in the LIBS item of the makefile. The following is a makefile that compiles a MultipleRM server program on 32-bit Linux.
# Oracle Env include $(ORACLE_HOME)/precomp/lib/env_precomp.mk ORALIBDIR = $(LIBHOME) ORALIB = $(PROLDLIBS) LIBDIR = lib32 # Server makefile TARGET = $(COMP_TARGET) TARGET2 = $(COMP_TARGET2) APOBJS = $(TARGET).o APOBJS2 = $(TARGET2).o NSDLOBJ = $(TMAXDIR)/lib/sdl.o MQLIBD = $(MQ_HOME)/lib #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 -lnsl -lnodb -lmqs -lmqmxa_r -lmqm_r -lm OBJS = $(APOBJS) $(APOBJS2) $(SVCTOBJ) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -v -m32 -O -I$(TMAXDIR) -I$(MQ_HOME)/inc APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib # .SUFFIXES : .c .c.o: $(CC) $(CFLAGS) -c $< # # server compile # all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(MQLIBD) -L$(ORALIBDIR) $(ORALIB) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(APOBJS2): $(TARGET2).pc proc iname=$(TARGET2) include=$(TMAXDIR) define=__LINUX_ORACLE_PROC__ $(CC) $(CFLAGS) -c $(TARGET2).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)
Makefile contents may vary depending on the operating system. |
TMS Makefile
The following is a makefile example to compile Oracle TMS on 32-bit Linux.
# TMS Makefile for Oracle # Linux include $(ORACLE_HOME)/precomp/lib/env_precomp.mk ORALIBDIR = $(LIBHOME) ORALIB = $(PROLDLIBS) $(LIBCLNTSH) LIBDIR = lib32 TARGET = tms_ora APOBJ = dumy.o APPDIR = $(TMAXDIR)/appbin TMAXLIBD= $(TMAXDIR)/lib TMAXLIBS= -ltms -loras #TMAXLIBS= -ltmsd -lorasd CFLAGS = -g -v -m32 CFLAGS = -m32 LDFLAGS = SYSLIBS = all : $(TARGET) $(TARGET): $(APOBJ) $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) -L$(TMAXLIBD) $(TMAXLIBS) $(APOBJ) -L$(ORALIBDIR) $(ORALIB) $(SYSLIBS) mv $(TARGET) $(APPDIR)/. $(APOBJ): $(CC) $(CFLAGS) -c dumy.c # clean: -rm -f *.o core $(APPDIR)/$(TARGET)
The following is a makefile example to compile MQ TMS on 32-bit Linux.
# TMS Makefile for MQ # Linux 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)
5. Using Two Tibero Instances
Two Tibero instances can be used in TCS through the server library. This section describes examples of programs that use two Tibero instances, environment configuration, and makefile for compilation.
5.1. Program Examples
The following example shows transaction processing on a single server that uses two Tibero RM instances.
Since the same Tibero client library is used, the user must specify the instance to use when executing a query from user code. To achieve this, Tibero allows obtaining and specifying the corresponding instance connection using the ESQL statement (EXEC SQL XA SET CONNECTION AT: conn_id).
Service Execution
The following is program source code that executes a service.
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> extern int SVC2301TX_1_tibero(TPSVCINFO *msg); SVC2301TX_1( TPSVCINFO *msg ) { int ret; int fail = 0; char *rcvbuf; rcvbuf=(char *)tpalloc("STRING", NULL, 4096); if(rcvbuf==NULL) { printf("tpalloc failed (rcvbuf) : %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, -1, NULL, 0, 0); } ret = SVC2301TX_1_tibero(msg); if (ret < 0) { fail = 1; } if ( fail ) { printf("SVC2301TX_1 FAIL\n"); tpreturn(TPFAIL,-1,NULL, 0,0); } strcpy(rcvbuf, "Multiple RM Insert Success"); tpreturn( TPSUCCESS, 0, rcvbuf, strlen(rcvbuf), 0 ); }
Tibero Call Function
The following program uses a function to call Tibero.
#include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.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 SQLOK 0 #define SQLDUP 1 #define SQLNOTFOUND 1403 EXEC SQL INCLUDE SQLCA.H; EXEC SQL BEGIN DECLARE SECTION; int h_empno; char h_ename[MAXLEN]; char h_job[MAXLEN]; char h_date[MAXLEN]; float h_sal; int h_count; char h_xid[100]; char h_conn_id[MAXLEN]; EXEC SQL END DECLARE SECTION; SVC2301TX_1_tibero( TPSVCINFO *msg ) { str sndbuf; char *rcvbuf; char tmp[1024]; TXINFO info; 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); } h_empno = h_sal = 0; memset( h_ename, 0x00, sizeof( h_ename ) ); memset( h_job, 0x00, sizeof( h_job ) ); memset( h_date, 0x00, sizeof( h_date ) ); memset( tmp , 0x00, sizeof( tmp ) ); memset( h_xid , 0x00, sizeof( h_xid ) ); memset( h_conn_id, 0x00, sizeof( h_conn_id ) ); h_empno = sndbuf->empno; h_sal = sndbuf->sal; strcpy( h_ename, sndbuf->ename ); strcpy( h_job , sndbuf->job ); strcpy( h_date , sndbuf->date ); if (tx_info(&info)==1) { sprintf(h_xid, "%x %x %x %x - %x %x %x %x", (unsigned char)info.xid.data[0], (unsigned char)info.xid.data[1], (unsigned char)info.xid.data[2], (unsigned char)info.xid.data[3], (unsigned char)info.xid.data[4], (unsigned char)info.xid.data[5], (unsigned char)info.xid.data[6], (unsigned char)info.xid.data[7]); printf("xid=[%s] \n", h_xid); } else { printf("Not in transaction \n"); tpreturn(TPFAIL, -1, NULL, 0, 0); } /* Set Default SQL CTX with conn_id */ strcpy(h_conn_id, "DB1"); EXEC SQL XA SET CONNECTION AT :h_conn_id; if (sqlca.sqlcode != SQLOK) { sprintf(tmp, "[%s] emp Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } EXEC SQL INSERT INTO tmax( empno, ename, job, hiredate,sal, xid) VALUES (:h_empno, :h_ename, :h_job, to_date(:h_date,'yymmdd'), :h_sal, :h_xid ); if ( sqlca.sqlcode != SQLOK ) { sprintf(tmp, "[%s] TIBERO tmax Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sleep(1); /* Set Default SQL CTX with conn_id */ strcpy(h_conn_id, "DB2"); EXEC SQL XA SET CONNECTION AT :h_conn_id; if (sqlca.sqlcode != SQLOK) { sprintf(tmp, "[%s] emp Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } EXEC SQL INSERT INTO tmax( empno, ename, job, hiredate,sal, xid) VALUES (:h_empno, :h_ename, :h_job, to_date(:h_date,'yymmdd'), :h_sal, :h_xid ); if ( sqlca.sqlcode != SQLOK ) { sprintf(tmp, "[%s] TIBERO tmax Insert Fail", msg->name); strcpy(rcvbuf, tmp); printf("[%s] %d \n", rcvbuf, sqlca.sqlcode); tpreturn( TPFAIL, sqlca.sqlcode, rcvbuf, strlen(rcvbuf), 0 ); } sprintf(tmp, "[%s] TIBERO tmax Insert Success", msg->name); strcpy(rcvbuf, tmp); return 0; }
5.2. Environment Configuration and Compilation
The following shows the environment configuration and compilation of MultipleRM that uses two Tibero instances.
Environment Configuration
The following is a MultipleRM server configuration example.
*DOMAIN domain SHMKEY = 81522, MAXUSER = 10000, MINCLH = 1, MAXCLH = 1, TPORTNO = 11500, BLOCKTIME = 30, MAXSACALL = 1024, MAXCACALL = 1024, MAXMTMAX = 3, MAXSTMAX = 10 *NODE node1 TMAXDIR = "/home/tmax1/tmax", APPDIR = "/home/tmax1/tmax/appbin", PATHDIR = "/home/tmax1/tmax/path", TLOGDIR = "/home/tmax1/tmax/log/tlog", ULOGDIR = "/home/tmax1/tmax/log/ulog", SLOGDIR = "/home/tmax1/tmax/log/slog" node2 TMAXDIR = "/home/tmax2/tmax", APPDIR = "/home/tmax2/tmax/appbin", PATHDIR = "/home/tmax2/tmax/path", TLOGDIR = "/home/tmax2/tmax/log/tlog", ULOGDIR = "/home/tmax2/tmax/log/ulog", SLOGDIR = "/home/tmax2/tmax/log/slog" *SVRGROUP svg_s1 NODENAME = node1, DBNAME = TIBERO, OPENINFO="TIBERO_XA:user=tibero,pwd=tmax,db=tibero1,Loose_Coupling=false,sestm=60,conn_id=DB1", TMSNAME = tms_tbr, SVGTYPE = STMAX, RMID = 1 svg_s2 NODENAME = node2, DBNAME = TIBERO, OPENINFO="TIBERO_XA:user=tibero,pwd=tmax,db=tibero2,Loose_Coupling=false,sestm=60,conn_id=DB2", TMSNAME = tms_tbr, SVGTYPE = STMAX, RMID = 2 svgm1 NODENAME = node1, SVGLIST = "svg_s1, svg_s2", SVGTYPE = MTMAX *SERVER svr2301TX SVGNAME = svgm1, MIN=5, MAX=5, MAXRSTART=-1 *SERVICE SVC2301TX_1 SVRNAME = svr2301TX, SVCTIME=5
Makefile
-lnodb must be included in the TMAXLIBS item of the makefile. The following is a makefile that compiles a MultipleRM server program on 64-bit Linux.
# Tibero Env TBINC = $(TB_HOME)/client/include TBLIBDIR = $(TB_HOME)/client/lib TBLIB = -ltbxa -ltbertl -ltbcli -lm -lpthread # Server makefile TARGET = $(COMP_TARGET) APOBJS = $(TARGET).o NSDLOBJ = $(TMAXDIR)/lib64/sdl.o AP_TBR_OBJS = $(TARGET)_tbr.o LIBS = -lsvr -lnsl -lnodb OBJS = $(AP_TBR_OBJS) $(APOBJS) $(SVCTOBJ) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -I$(TMAXDIR) APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib64 # .SUFFIXES : .c .c.o: $(CC) $(CFLAGS) -c $< # # server compile # all: $(TARGET) $(TARGET): $(OBJS) echo $(ORALIBDIR) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -o $(TARGET) -L$(TBLIBDIR) $(TBLIB) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(AP_TBR_OBJS): echo $(OBJS) tbpc iname=$(TARGET)_tbr.tbc include=$(TMAXDIR) $(CC) $(CFLAGS) -I$(TBINC) -c $(TARGET)_tbr.c $(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)
Makefile contents may vary depending on the operating system. |