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 = -lclntsh `cat /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. 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 = -lclntsh `cat /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 내용은 다를 수 있다. |
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); f(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; }
Multiple RM에서는 xa dynamic registration을 지원하지 않기 때문에 업무적으로 select 문을 호출하더라도 항상 tx_begin()을 호출해야 한다. 또는 select 문을 처리하는 서비스를 insert, update, delete를 수행하는 서비스를 가지지 않는 별도의 서버로 분리해서 처리해야 정상 동작한다. |
3.2. 환경설정 및 컴파일
Oracle과 Tibero를 사용하는 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 내용은 다를 수 있다. |