MultipleRM 프로그램 예제
본 장에서는 TCS에서 MultipleRM 프로그램 예제와 환경설정, 컴파일을 위한 Makefile의 예제에 대해서 설명한다.
1. Oracle과 Tibero 사용
서버 라이브러리를 이용하여 TCS에서 Oracle과 Tibero를 사용할 수 있다. 본 절에서는 Oracle과 Tibero를 사용하는 프로그램의 예제와 환경설정, 컴파일을 위한 Makefile의 예제를 설명한다.
1.1. 프로그램 예제
다음은 Oracle과 Tibero를 함께 사용하는 TCS 예제 프로그램이다. Embedded SQL을 이용하여 서버를 작성하고 각 데이터베이스 벤더에서 제공하는 프리 컴파일러로 컴파일하여 구성할 수 있는 프로그램 예제이다.
서비스 수행
다음은 서비스를 수행하는 프로그램의 소스이다.
#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 호출 함수
다음은 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 호출 함수
다음은 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. 환경설정
Oracle과 Tibero를 사용하는 MultipleRM의 환경설정 예제를 설명한다.
*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. 컴파일
본 절에서는 Oracle과 Tibero를 사용하는 MultipleRM의 컴파일 예제를 설명한다.
프로그램을 빌드할 때 _tmax_xasw_init() 함수가 정의된 라이브러리(예: liboras.so)가 링크되어 있는 경우 RM 파일의 라이브러리에서 목록 추출하는 방법의 동작을 따른다. 그렇지 않은 경우에는 설정 파일에 정의된 내용을 따르는 방법의 동작을 따른다. Makefile 내의 LIBS(TMAX라이브러리)에 반드시 -lnodb를 포함해야 한다.
|
운영체제에 따라 Makefile 내용은 다를 수 있다. |
다음은 32bit Linux에서 MultipleRM 서버 프로그램을 컴파일하기 위한 Makefile의 예제이다.
# Oracle Env ORALIBDIR = /home/OraHome1/lib/ ORALIB = -lclntshcat /home/OraHome1/lib/ldflagscat /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. Oracle과 Oracle 사용
서버 라이브러리를 이용하여 TCS에서 Oracle과 Oracle을 사용할 수 있다. 본 절에서는 Oracle과 Oracle을 사용하는 프로그램의 예제와 환경설정, 컴파일을 위한 Makefile의 예제를 설명한다.
2.1. 프로그램 예제
다음은 2개의 RM이 모두 Oracle이지만 인스턴스가 다른 경우에 한 서버에서 처리하는 예제이다.
같은 Oracle 클라이언트 라이브러리를 사용하기 때문에 사용자 코드에서 쿼리를 수행할 경우 어떤 인스턴트를 수행할지는 사용자가 지정해야 한다. 이를 위해서 Oracle에서는 xa_open의 경우 사용자 코드에서 xaoSvcCtx, xaoEnv 등의 OCI 함수를 이용하여 해당하는 인스턴트 커넥션을 얻어와서 지정할 수 있다.
서비스 수행
다음은 서비스를 수행하는 프로그램의 소스이다.
#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 호출 함수
다음은 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. 환경설정 및 컴파일
Oracle과 Oracle을 사용하는 MultipleRM의 환경설정 및 컴파일 예제를 설명한다.
환경설정
다음은 MultipleRM 서버의 환경설정 파일의 예제이다.
*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
Makefile의 TMAXLIBS에 반드시 -lnodb를 포함해야 한다. 다음은 32bit Linux에서 MultipleRM 서버 프로그램을 컴파일하기 위한 Makefile의 예이다.
# Oracle Env ORALIBDIR = /home/OraHome1/lib/ ORALIB = -lclntshcat /home/OraHome1/lib/ldflagscat /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 내용은 다를 수 있다. |
3. Oracle과 DB2 사용
서버 라이브러리를 이용하여 TCS에서 Oracle과 DB2를 사용할 수 있다. 본 절에서는 Oracle과 DB2를 사용하는 프로그램의 예제와 환경설정, 컴파일을 위한 Makefile의 예제를 설명한다.
3.1. 프로그램 예제
다음은 Oracle과 DB2를 함께 사용하는 TCS 예제 프로그램이다. Embedded SQL을 이용하여 서버를 작성하고 각 데이터베이스 벤더에서 제공하는 프리 컴파일러로 컴파일하여 구성할 수 있는 프로그램 예제이다.
서비스 수행
다음은 서비스를 수행하는 프로그램의 소스이다.
#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 호출 함수
다음은 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 호출 함수
다음은 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;
}
|
MultipleRM에서는 xa dynamic registration을 지원하지 않기 때문에 업무적으로 select 문을 호출하더라도 항상 tx_begin()을 호출해야 한다. 혹은 select 문을 처리하는 서비스를 insert, update, delete를 수행하는 서비스를 가지지 않는 별도의 서버로 분리해서 처리해야 정상 동작한다. |
3.2. 환경설정 및 컴파일
Oracle과 DB2를 사용하는 MultipleRM의 환경설정 및 컴파일 예제를 설명한다.
환경설정
다음은 MultipleRM 서버의 환경설정 파일의 예제이다.
*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
Makefile 내의 LIBS(TMAX라이브러리)에 반드시 -lnodb를 포함해야 한다.
다음은 64bit Linux에서 MultipleRM 서버 프로그램을 컴파일하기 위한 Makefile의 예제이다.
# 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 내용은 다를 수 있다. |
4. Oracle과 MQ 사용
서버 라이브러리를 이용하여 TCS에서 Oracle과 MQ를 사용할 수 있다. 본 절에서는 Oracle과 MQ를 사용하는 프로그램의 예제와 환경설정, 컴파일을 위한 Makefile의 예제를 설명한다.
4.1. 프로그램 예제
다음은 Oracle과 MQ를 함께 사용하는 TCS 예제 프로그램이다. Embedded SQL을 이용하여 서버를 작성하고 각 데이터베이스 벤더에서 제공하는 프리 컴파일러로 컴파일하여 구성할 수 있는 프로그램 예제이다.
MQ 호출 함수
다음은 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 호출 함수
다음은 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. 환경설정 및 컴파일
Oracle과 MQ를 사용하는 MultipleRM의 환경설정 및 컴파일 예제를 설명한다.
환경설정
다음은 MultipleRM 서버의 환경설정 파일의 예제이다.
*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
Makefile 내의 LIBS(TMAX라이브러리)에 반드시 -lnodb를 포함해야 한다.
다음은 32bit Linux에서 MultipleRM 서버 프로그램을 컴파일하기 위한 Makefile의 예제이다.
# 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 내용은 다를 수 있다. |
TMS Makefile
다음은 32bit Linux에서 ORACLE TMS을 컴파일하기 위한 Makefile의 예제이다.
# 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)
다음은 32bit Linux에서 MQ TMS을 컴파일하기 위한 Makefile의 예제이다.
# 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. Tibero와 Tibero 사용
서버 라이브러리를 이용하여 TCS에서 Tibero와 Tibero을 사용할 수 있다. 본 절에서는 Tibero와 Tibero을 사용하는 프로그램의 예제와 환경설정, 컴파일을 위한 Makefile의 예제를 설명한다.
5.1. 프로그램 예제
다음은 2개의 RM이 모두 Tibero이지만 인스턴스가 다른 경우에 한 서버에서 처리하는 예제이다.
같은 Tibero 클라이언트 라이브러리를 사용하기 때문에 사용자 코드에서 쿼리를 수행할 경우 어떤 인스턴트를 수행할지는 사용자가 지정해야 한다. 이를 위해서 Tibero에서는 ESQL문(EXEC SQL XA SET CONNECTION AT :conn_id)을 이용하여 해당하는 인스턴트 커넥션을 얻어와서 지정할 수 있다.
서비스 수행
다음은 서비스를 수행하는 프로그램의 소스이다.
#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 호출 함수
다음은 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. 환경설정 및 컴파일
Tibero와 Tibero을 사용하는 MultipleRM의 환경설정 및 컴파일 예제를 설명한다.
환경설정
다음은 MultipleRM 서버의 환경설정 파일의 예제이다.
*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
Makefile의 TMAXLIBS에 반드시 -lnodb를 포함해야 한다. 다음은 64bit Linux에서 MultipleRM 서버 프로그램을 컴파일하기 위한 Makefile의 예이다.
# 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 내용은 다를 수 있다. |