제5장 예제

내용 목차

5.1. 통신 유형 예제
5.1.1. 동기형 통신
5.1.2. 비동기형 통신
5.1.3. 대화형 통신
5.2. 전역 트랜잭션 프로그램 예제
5.3. 데이터베이스 프로그램
5.3.1. Oracle Insert 프로그램
5.3.2. Oracle Select 프로그램
5.3.3. Informix Insert 프로그램
5.3.4. Informix Select 프로그램
5.4. 데이터베이스 연동 프로그램
5.4.1. 동기형 모드(동일 기종)
5.4.2. 동기형 모드(이기종)
5.4.3. 비동기형 모드(동일 기종)
5.4.4. 대화형 모드(동일 기종)
5.5. TIP를 이용한 프로그램
5.5.1. TIP 구조
5.5.2. TIP 사용
5.5.3. TIP 사용 예제
5.5.4. 시스템 환경 정보 조회 프로그램
5.5.5. 시스템 통계 정보 조회 프로그램
5.5.6. 서버 프로세스 기동 및 종료 프로그램
5.6. Local recursive call

본 장에서는 Tmax 시스템에서 제공하는 고유의 기능을 사용하기 위한 예제를 설명한다.

5.1. 통신 유형 예제

본 절에서는 Tmax에서 사용하는 3가지 통신형인 동기형, 비동기형, 대화형 애플리케이션의 간단한 예제를 통해 전체적인 흐름에 대해 설명한다.

5.1.1. 동기형 통신

클라이언트는 STRING 버퍼에 문자열을 복사해서 서비스를 호출하고, 서버의 서비스 루틴은 이 문자열을 받아서 대문자열로 바꾸어 반환하는 프로그램이다.

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    sample.mTmax 환경설정 파일이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    sync_cli.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    syncsvc.c대문자로 바꾸는 서비스 프로그램이다.
    MakefileTmax에서 제공되는 Makefile로 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 연결기본 연결(클라이언트 정보 없음)
    버퍼 유형STRING
    통신 유형tpcall()을 이용한 동기형 통신
  • 서버 프로그램

    기능설명
    서비스TOUPPERSTR
    데이터베이스 연결없음

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

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

*SVRGROUP
svg1          NODENAME = tmax

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

*SERVICE
TOUPPERSTR    SVRNAME = syncsvc

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<sync_cli.c>

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

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

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

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

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

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

       strcpy(sendbuf ,argv[ 1 ] ) ;

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

서버 프로그램

다음은 서버 프로그램의 예제이다.

<syncsvc.c>

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

TOUPPERSTR(TPSVCINFO *msg)
{
       int i;

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

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

5.1.2. 비동기형 통신

클라이언트는 STRUCT 버퍼의 멤버에 문자열을 복사해서 서비스를 호출하고, 서버의 서비스 루틴은 이 문자열을 받아서 소문자열 혹은 대문자열로 바꾸어 반환하는 프로그램이다. 클라이언트는 비동기형 통신으로 TOUPPER 서비스를 요청하고 다시 동기형으로 TOLOWER 서비스를 호출하여 결과를 받은 후 앞서 요청한 TOUPPER 서비스의 수행 결과를 받는다.

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.s구조체 버퍼를 정의한다.
    sample.mTmax 환경설정 파일이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    async_cli.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    asyncsvc.c대문자/소문자로 바꾸는 서비스 프로그램이다.
    MakefileTmax에서 제공되는 Makefile로 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 연결기본 연결
    버퍼 유형STRUCT
    통신 유형동기형 및 비동기형
  • 서버 프로그램

    기능설명
    서비스TOUPPER, TOLOWER
    데이터베이스 연결없음
    통신 유형동기형 및 비동기형

구조체 버퍼

다음은 비동기형 통신에서 사용하는 구조체 버퍼이다.

<demo.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일 예제이다.

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

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

*SVRGROUP
svg1          NODENAME = tmax

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

*SERVICE
TOUPPER        SVRNAME = asyncsvc
TOLOWER        SVRNAME = asyncsvc

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<async_cli.c>

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

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

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

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

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

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

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

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

서버 프로그램

다음은 서버 프로그램의 예제이다.

<asyncsvc.c>

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

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

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

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

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

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

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

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

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

5.1.3. 대화형 통신

클라이언트는 사용자의 입력을 받아 STRING 버퍼를 통해 고유번호를 보내며, 서버의 서비스 루틴은 데이터베이스에 저장된 테이블에서 그 고유번호보다 큰 번호를 가지는 고객정보를 구조체를 통해 반환한다.

클라이언트는 대화형 모드를 설정하면서 고유번호를 보내며 대화 주도권은 서버에 넘긴다. 서버는 조건을 만족하는 데이터베이스의 모든 데이터를 커서를 통해 읽어서 클라이언트로 보낸다. 클라이언트는 TPEVSVCSUCC를 통해 이상없이 모든 데이터를 읽어왔다는 것을 확인할 수 있다.

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.s구조체를 정의한 파일이다.
    sample.mTmax 환경설정 파일이다.
    mktable.sql테이블 생성 스크립트이다.
    sel.sql테이블 및 데이터 출력 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    conv_cli.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    convsvc.pc서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 연결기본 연결
    버퍼 유형보낼 때 STRING, 받을 때 STRUCT
    통신 유형대화형 통신TRUCT
  • 서버 프로그램

    기능설명
    서비스MULTI
    데이터베이스 연결Oracle 사용

구조체 버퍼

다음은 대화형 통신에서 사용하는 구조체 버퍼이다.

<demo.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

* DOMAIN
resrc        SHMKEY = 77990, MAXUSER = 256

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

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

*SERVER
convsvc       SVGNAME = svg1, CONV = Y

*SERVICE
MULTI         SVRNAME = convsvc

다음은 환경설정에 추가된 항목에 대한 설명이다.

항목설명
DBNAME사용하는 데이터베이스명을 정의한다.
OPENINFOOracle 데이터베이스와 연동하기 위한 연결 정보를 설정한다.
TMSNAME전역 트랜잭션 처리를 주재하는 프로세스명을 설정한다.
CONV대화형 모드 서버를 지정한다.

데이터베이스 스크립트

다음은 Oracle 테이블 생성 스크립트의 예제이다.

<mktable.sql>

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

다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.

<sel.sql >

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<conv_cli.c>

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

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

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

       /* tpstart()와 함께 Tmax에 연결함. */
       if (tpstart((TPSTART_T *) NULL) == -1) {
              printf("tpstart failed\n");
              exit(1);
       }

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

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

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

      /* 대화형 통신 연결, 대화 주도권은 서버 측에 넘김 */
       printf("tpconnect SUCESS \"MULTI\" service\n");
       while ( 1 ) {    /* 다중 데이터 수신. */
              printf("tprecv strat\n");
              if( tprecv(cd, (char **)&rcvbuf, &rcvlen, TPNOTIME, &revent) < 0 ) {
              /* 서버에서 tpreturn()으로 끝냈다면 */
              if (revent == TPEV_SVCSUCC){
                     printf("all is completed\n");
                     break;
              }       
              printf("tprecv failed, tperrno=%s, revent=%x\n",
              tpstrerror(tperrno), revent );
              tpfree(sndbuf);
              tpfree((char *)rcvbuf);
              tpend();
              exit(1);
       }
       printf("seqno = %s\t\t corpno =%s\n", rcvbuf->seqno, rcvbuf->corpno);
       printf("compdate = %s\t\t totmon =%d\n", rcvbuf->compdate, rcvbuf->totmon);
       printf("guarat = %f\t\t guamon =%f\n\n\n", rcvbuf->guarat, rcvbuf->guamon) ;
}
       tpfree(sndbuf);
       tpfree((char *)rcvbuf);
       tpend();
       printf("FINISH\n");
}

서버 프로그램

다음은 서버 프로그램의 예제이다.

<convsvc.pc>

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

EXEC SQL begin declare section; /* Oracle 전역 변수 선언 */
       char seq[10];
       struct sel_o *sndbuf;
EXEC SQL end declare section;
EXEC SQL include sqlca;

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

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

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

       /* 다량 데이터 위해 커서 선언 */
       EXEC SQL declare democursor cursor for 
       select *
       from corp
       where seqno > :seq;

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

        /* Oracle 에러가 없는 동안 데이터 전송 */
       while ( sqlca.sqlcode == 0 ){
              EXEC SQL fetch democursor into :sndbuf;

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

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

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

5.2. 전역 트랜잭션 프로그램 예제

전역 트랜잭션(Global Transaction Processing)이란 하나 이상의 자원 관리자(데이터베이스)와 하나 이상의 물리적인 사이트가 하나의 논리적인 단위로 참여하는 트랜잭션이다. Tmax 시스템에서는 모든 트랜잭션을 일단 전역 트랜잭션으로 간주하며, 데이터의 무결성을 위해 2PC(2 Phase Commit)를 사용한다.

클라이언트는 사용자의 입력을 받아 구조체 버퍼를 통해 고유번호와 데이터를 보내며 서버는 해당 고유번호의 데이터를 업데이트하고 이 데이터로 다른 데이터베이스를 사용하는 서비스를 호출하여 테이블에 추가한다. 클라이언트는 이 모든 과정을 하나의 트랜잭션으로 지정하여 에러가 발생했을 경우 2개의 데이터베이스를 동시에 Rollback할 수 있도록 한다.

[그림 5.1] 2개의 데이터베이스 접속

2개의 데이터베이스 접속


프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.s구조체 버퍼 설정 파일이다.
    sample.mTmax 환경설정 파일이다.
    mktable.sql데이터베이스에 테이블로 생성하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    update.pc데이터베이스에 업데이트하는 서버 프로그램이다.
    insert.pc데이터베이스에 INSERT하는 서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

프로그램 특징

  • 클라이언트 부분

    기능설명
    Tmax 접속기본 접속
    버퍼 유형STRUCT
    통신 유형tpcall()에 의한 동기 통신
    트랜잭션 처리클라이언트에서 트랜잭션 범위 지정
  • 서버 부분

    기능설명
    서버 프로그램서로 다른 데이터베이스를 사용하는 2개의 서버 프로그램
    서비스UPDATE, INSERT
    데이터베이스 연결2종류의 Oracle 데이터베이스

구조체 버퍼

다음은 전역 트랜잭션에서 사용하는 구조체 버퍼이다.

<demo.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

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

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

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


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

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

*SERVER
update       SVGNAME=svg1
insert       SVGNAME=svg2

*SERVICE
UPDATE       SVRNAME=update
INSERT       SVRNAME=insert

데이터베이스 스크립트

다음은 Oracle 테이블 생성 스크립트의 예제이다.

<mktable.sql>

sqlplus scott/tiger << EOF
drop table ACCOUNT;

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

클라이언트 프로그램

다음은 클라이언트 프로그램 예제이다.

<client.c >

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

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

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

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

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

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

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

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

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

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

서버 프로그램

다음은 데이터베이스에 업데이트하는 서버 프로그램의 예제이다.

<update.pc>

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

#define OKMSG "YOU COMPLETE THE TRANSACTION"

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

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

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

    EXEC SQL UPDATE ACCOUNT
                SET BRANCH_ID = :branch_id,
                    PHONE = :phone,
                    ADDRESS = :address,
                    SSN = :ssn
              WHERE ACCOUNT_ID = :account_id;
    if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) {
        fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode);
        tpreturn(TPFAIL, -1, (char *)NULL, 0, 0);
    }
    rcvbuf->account_id++;
    ret = tpcall("INSERT", (char *)rcvbuf, 0, (char **)&send, (long *)&rcvlen, 
                 TPNOFLAGS);
    if (ret < 0) {
        fprintf(stderr, "tpcall fail tperrno = %d\n", tperrno);
        tpreturn(TPFAIL, -1, (char *)NULL, 0, 0);
    }
    strcpy(send, OKMSG);
    tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS);
}

다음은 데이터베이스에 INSERT하는 서버 프로그램의 예제이다.

<insert.pc>

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

#define OKMSG "YOU COMPLETE THE TRANSACTION"

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

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

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

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

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

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

5.3. 데이터베이스 프로그램

대표적인 데이터베이스인 Oracle과 Informix를 사용하는 몇 가지 예제를 제시한다.

5.3.1. Oracle Insert 프로그램

클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이를 받아 해당 테이블에 추가한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.s구조체 버퍼 설정 파일이다.
    sample.mTmax 환경설정 파일이다.
    mktable.sql데이터베이스 테이블을 생성하는 SQL 스크립트이다.
    sel.sql데이터베이스 테이블 내용을 출력하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    oins_cli.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    oinssvc.pc서비스 프로그램의 Oracle 소스이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 접속기본 접속
    버퍼 유형STRUCT
    통신 유형tpcall()에 의한 동기 통신
    트랜잭션 처리클라이언트에서 트랜잭션 범위 지정
  • 서버 프로그램

    구분설명
    서비스ORAINS
    데이터베이스 연결Oracle 데이터베이스

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

*DOMAIN
resrc             SHMKEY = 77990, MAXUSER = 256

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

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

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

*SERVICE
ORAINS            SVRNAME = oinssvc

다음은 환경설정에 추가된 항목에 대한 설명이다.

항목설명
DBNAME사용하는 데이터베이스를 정의한다.
OPENINFOOracle 데이터베이스 연결 정보를 설정하는 항목으로 Oracle 데이터베이스인 경우 CLOSEINFO는 지정하지 않아도 된다. tpsvrinfo()에서 호출한다.
TMSNAME트랜잭션 처리를 주재하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션을 처리한다. svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다.

데이터베이스 스크립트

다음은 Oracle 테이블 생성 스크립트의 예제이다.

<mktable.sql>

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

다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.

<sel.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<oins_cli.c>

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

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

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

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

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

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

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

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

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

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

서버 프로그램

다음은 서버 프로그램의 예제이다.

<oinssvc.pc>

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

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

EXEC SQL end declare section;
EXEC SQL include sqlca;

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

       /* 데이터베이스에 삽입 */
       EXEC SQL insert into testdb1(no, name) values(:no, :name);

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

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

5.3.2. Oracle Select 프로그램

클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이에 해당하는 모든 데이터를 받아 구조체 배열을 사용하여 결과를 반환한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.

프로그램 구성

  • 공통 프로그램

    구성설명
    demo.s구조체 버퍼 설정 파일이다.
    sample.mTmax 시스템 환경 파일이다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
    sel.sql데이터베이스 테이블 내용을 출력하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    구성설명
    oins_cli.c클라이언트 프로그램이다.
    cdata.c클라이언트 사용 함수 모듈이다.
  • 서버 프로그램

    구성설명
    oselsvc.pc서비스 프로그램 Oracle 소스이다.
    MakefileTmax에서 제공되는 Makefile로 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 접속기본 접속
    서비스ORASEL
    버퍼 유형STRUCT
    통신 유형tpcall()에 의한 동기 통신
    트랜잭션 처리클라이언트에서 트랜잭션 범위 지정
  • 서버 프로그램

    기능설명
    서비스ORASEL
    데이터베이스 연결Oracle 데이터베이스
    버퍼사용필요에 의해 버퍼 크기 재조정

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

struct stru_his{
       long    ACCOUNT_ID ;
       long    TELLER_ID ;
       long    BRANCH_ID ;
       long    AMOUNT ;
} ;

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

*DOMAIN
resrc             SHMKEY = 77990, MAXUSER = 256

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

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

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

*SERVICE
ORASEL            SVRNAME = oselsvc

다음은 환경설정에 추가된 항목에 대한 설명이다.

항목설명
DBNAME사용할 데이터베이스명을 설정한다.
OPENINFOOracle 데이터베이스 연결 정보를 설정하는 항목으로 Oracle에서는 CLOSEINFO는 설정하지 않아도 된다. 사용가능한 옵션은 표 이후에 설명한다.
TMSNAME트랜잭션 처리를 관리하는 프로세스명을 지정한다.
AUTOTRAN해당 서비스를 처리할 때 자동으로 트랜잭션 상태로 처리한다.

다음은 OPENINFO 항목에서 사용할 수 있는 옵션으로 LogDir과 DbgFl을 사용할 수 있다.

옵션설명
LogDir

LogDir을 지정하면 지정된 곳에 XA에 관련된 로그를 남길 수 있다.

LogDir을 지정하지 않으면 $ORACLE_HOME/rdbms/log 또는 현재 디렉터리에 <xa_NULL날짜.trc> 파일이 생성된다.

DbgFl몇 번째 단계의 디버그 flags를 설정할지를 결정한다. 기본적인 단계인 0x01 또는 OCI 단계인 0x04 등을 사용하면 된다.

다음은 OPENINFO 항목의 옵션으로 LogDir과 DbgFl을 사용하는 예제이다.

OPENINFO=“Oracle_XA+Acc=P/계정/암호 +SesTm=60+LogDir=/tmp+DbgFl=0x01”

주의

개발할 때에는 디버그 모드를 해제하고 사용해야만 나중에 디스크가 Full되는 상황을 피할 수 있다.

데이터베이스 스크립트

다음은 Oracle 테이블 작성 스크립트의 예제이다.

<mktable.sql>

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

다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.

<sel.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<oins_cli.c>

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

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

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

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

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

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

       /* 트랜잭션 타임아웃 설정 */
       tx_set_transaction_timeout(30);        
       
       /* 글로벌 트랜잭션 시작 */
       if (tx_begin() < 0) {                      
              fprintf(stderr, “tx_begin() failed ->%s!\n”,
              tpstrerror(tperrno));
              tpfree((char*)transf);
              tpend();
              exit(0) ;
       }

       if (tpcall(“ORASEL”,(char *)transf, 0, (char **)&transf, &nrecv,
                  TPNOFLAGS)== -1){
              /* 동기 통신으로 “ORASEL” 서비스 요청 */
              fprintf(stderr,“Tpcall(SELECT...)error->%s ! ”,
              tpstrerror(tperrno)) ;
              tpfree((char *)transf);
              /* 실패시 트랜잭션 취소 */
              tx_rollback();               
              tpend();
              exit(0) ;
       }
       /* 성공시 트랜잭션 Commit */
       if (tx_commit() == -1) {       
              fprintf(stderr, “tx_commit() failed ->%s!\n”,
              tpstrerror(tperrno)) ;
              tpfree((char *)transf);
                     tpend();
                     exit(0) ;
       }
        /* 받아온 데이터는 구조체의 배열이다. */
       for (j =0 ; j < tpurcode ; j++) {
              /* Oracle에서 셀렉트한 데이터 결과를 프린트 */
              if (j == 0) 
                     printf(“%-12s%-10s%-10s%-10s\n”, 
                    “ACCOUNT_ID”,“TELLER_ID”, “BRANCH_ID”, “AMOUNT”);
              account_id=transf[j].ACCOUNT_ID;
              teller_id=transf[j].TELLER_ID;
              branch_id=(*(transf+j)).BRANCH_ID;
              amount=transf[j].AMOUNT;
       printf(“%-12d %-10d %-10d %-10d\n”, account_id, teller_id,branch_id, amount);
       } 
       /* 셀렉트한 데이터가 없거나 끝이라면 */
       if (urcode == NOTFOUND) {
       printf(“No records selected!\n”);
              tpfree((char *)transf);
              tpend();
              return 0;
}
       tpfree((char *)transf);
       tpend();
}

서버 프로그램

다음은 서버 프로그램의 예제이다.

<oselsvc.pc>

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

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

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

       /* msg 버퍼의  내용을  프로그램 변수에 전달. */
       key = transf->ACCOUNT_ID;

        /* transf 버퍼의 크기를 재조정 */
       if((transf=(struct stru_his *) tprealloc((char*)transf,
       sizeof(struct stru_his) * NARRAY ))==(struct stru_his*)NULL){
              fprintf(stderr, “tprealloc error ->%s\n”,
              tpstrerror(tperrno));
              tpreturn(TPFAIL, tperrno, NULL, 0, TPNOFLAGS);
              }           
       EXEC SQL select account_id, teller_id, branch_id, amount
                  into :account_id, :teller_id, :branch_id, :amount  from sel_his
                 where account_id > :key
              /* account_id가 client에서 보낸 key값 보다 큰 것을 */
              order by account_id;       /* global 변수에 넣어줌 */

       /* sql error 체크 (셀렉트된 것이 없거나 너무 많은 것 제외.) */
       if (sqlca.sqlcode!=0 && sqlca.sqlcode!=NOTFOUND && sqlca.sqlcode!=TOOMANY) {
              fprintf(stderr,“SQL ERROR ->NO(%d):%s\n”, sqlca.sqlcode,
              sqlca.sqlerrm.sqlerrmc) ;
              tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }           

       /* access한 개수를 lastno에 넣어줌 */
       lastno = sqlca.sqlerrd[2];    

       /* 셀렉트된 데이터가 너무 많음 */
       if (sqlca.sqlcode == TOOMANY)   
              lastno =rowno;

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

        /* Oracle에서 셀렉트한 데이터를 전송할 버퍼에 넣어줌 */
        for ( i = 0 ; i < lastno; i++) {
              transf[i].ACCOUNT_ID = account_id[i];
              transf[i].TELLER_ID = teller_id[i];
              transf[i].BRANCH_ID = branch_id[i];
              transf[i].AMOUNT = amount[i];
       }           
       tpreturn(TPSUCCESS, lastno, transf, i * sizeof(struct stru_his),
       TPNOFLAGS );
}

5.3.3. Informix Insert 프로그램

클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이를 받아 해당 테이블에 추가한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생한 경우 Rollback한다.

Informix 애플리케이션을 컴파일하기 전 다음 사항을 먼저 확인한다.

  1. UNIX 환경을 확인한다( .profile,.login, .cshrc ).

    다음과 같이 설정한다.

    INFORMIXDIR=/home/informix
    INFORMIXSERVER=tmax
    ONCONFIG=onconfig
    PATH=$INFORMIXDIR/bin: …
    LD_LIBRARY_PATH=/home/informix/lib:/home/informix/lib/esql:
    …
  2. Makefile을 확인한다.

    다음 오퍼레이션과 설정을 확인한다.

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

    <TMS Makefile>

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

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.s구조체 버퍼 설정 파일이다.
    sample.mTmax 시스템 환경 파일이다.
    mkdb.sql데이터베이스 생성 SQL 스크립트로 XA 모드는 데이터베이스가 로깅 모드에서 생성될 때 지원한다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
    sel.sql데이터베이스 테이블에 내용을 출력하는 SQL 스크립트이다.
    info.sSDLFILE이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    구성설명
    tdbsvr.ec서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 접속기본 접속
    버퍼 유형STRUCT
    통신 유형tpcall()에 의한 동기 통신
    트랜잭션 처리클라이언트에서 트랜잭션 범위 지정
  • 서버 프로그램

    기능설명
    서비스INSERT
    데이터베이스 연결Informix 데이터베이스

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

*DOMAIN 
resrc            SHMKEY = 77990, MAXUSER = 256 

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

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

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

*SERVICE 
INSERT         SVRNAME = tdbsvr

다음은 환경 설정에 추가된 항목에 대한 설명이다.

항목설명
DBNAME사용할 데이터베이스명을 설정한다.
OPENINFO, CLOSEINFOInformix 데이터베이스 연결 및 해제를 위한 정보를 tpsvrinfo(), tpsvrdone()에서 호출한다.
TMSNAME트랜잭션을 처리하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션 처리 svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다.

데이터베이스 스크립트

다음은 Informix 테이블 생성 스크립트의 예제이다.

<mktable.sql>

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

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

create unique index idx_tdb1 on testdb1(seq);
EOF

다음은 Informix 테이블 및 데이터 출력 스크립트의 예제이다.

<sel.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<client.c>

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

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

      /* 응용프로그램에서 사용할 버퍼 메모리 할당. */
     if ((transf=(struct info *)tpalloc ("STRUCT","info",0))==(struct info *)NULL){
          fprintf(stderr, “tpalloc(struct info, ...) failed ->%s!\n”,
          tpstrerror(tperrno)) ;
          tpend();
          exit(1) ;
       }

       /* 전송할 데이터 필드를 채움. */
       strcpy(transf->seq, “000001”);               
       strcpy(transf->data01, “Hello”);              
       strcpy(transf->data02, “World”);
       strcpy(transf->data03, “1234”);

        /* 트랜잭션 timeout 설정 * /
       tx_set_transaction_timeout (30);        

       /* 트랜잭션 시작을 알림. */
       if (tx_begin() < 0) { 
              fprintf(stderr, “tx_begin() failed ->%s!\n”,
              tpstrerror(tperrno)) ;
              tpfree ((char *)transf);
              tpend( ); exit(0);
       }

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

      /* 트랜잭션 성공. */
     if (tx_commit () < 0) { 
          fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ;
          tpfree ((char *)transf); 
          tpend( ); 
          exit(0);
       }

       tpfree ((char *)transf );
       /* Tmax 연결을 끊음. */
       tpend( ) ; 
}

서버 프로그램

다음은 서버 프로그램의 예제이다.

< tdbsvr.ec>

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

EXEC SQL include sqlca.h;

/* 서비스 명*/
INSERT(TPSVCINFO *msg)   
{
      /* 프로그램상의 버퍼 형식 선언. */
      struct info *INFO;   

       /* SQL문 내의 버퍼 형식 선언. */
       EXEC SQL begin declare section;         
       varchar seq[8],buf01[128],buf02[128],buf03[128];
       EXEC SQL end declare section;

       /* 메시지 버퍼로부터 구조체형으로 데이터를 전달받는다. */
       INFO = (struct info *)msg -> data;

       /* 구조체 형식으로 전달받은 데이터를 데이터베이스 버퍼로 복사. */
       strcpy(seq, INFO->seq);
       strcpy(buf01, INFO->data01);
       strcpy(buf02, INFO->data02);
       strcpy(buf03, INFO->data03);

      /* SQL문의 insert 수행 */
       EXEC SQL insert into testdb1 (seq,data01,data02,data03)
       values(:seq, :buf01, :buf02, :buf03);

      /* 에러가 발생한다면 */
       if ( sqlca.sqlcode ! = 0)  {
             /* Insert 실패를 알린다. */
              printf(“SQL error => %d !” ,sqlca.sqlcode);
              tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS);
       }

       /* Insert가 성공적으로 끝났을 때 */
       tpreturn (TPSUCCESS, 0, NULL, 0, TPNOFLAGS);
}

5.3.4. Informix Select 프로그램

클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이에 해당하는 모든 데이터를 받아 구조체 배열을 사용하여 결과를 반환한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    acct.sSDLFILE이다.
    sample.mTmax 환경 파일이다.
    mkdb.sql데이터베이스를 생성하는 SQL 스크립트이다.
    mktables.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
    sel.sql데이터베이스 테이블에 내용을 출력하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    구성설명
    client.c클라이언트 프로그램이다.
    cdate.cclient.c에서 사용된 함수 모듈이다.
  • 서버 프로그램

    구성설명
    sel_acct.ec서비스 프로그램 Informix 소스이다.
    MakefileTmax에서 제공되는 Makefile을 수정한다.

프로그램 특징

  • 클라이언트 프로그램

    구분설명
    Tmax 접속기본 접속
    버퍼 유형STRUCT
    통신 유형tpcall()에 의한 동기 통신
    트랜잭션 처리클라이언트에서 트랜잭션 범위 지정
  • 서버 프로그램

    구분설명
    서비스SEL_ACCT
    데이터베이스 연결Informix 데이터베이스
    버퍼 사용필요에 의해 버퍼 크기 재조정

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<acct.s>

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

Tmax 환경 파일

다음은 Tmax 환경 파일의 예제이다.

<sample.m>

*DOMAIN
resrc         SHMKEY = 77990, MAXUSER = 256

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

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

*SERVICE
SEL_ACCT      SVRNAME = sel_acct

다음은 환경 설정에 추가된 항목에 대한 설명이다.

항목설명
DBNAME사용할 데이터베이스를 설정한다.
OPENINFO, CLOSEINFOInformix 데이터베이스에 연결 및 해제를 위한 정보를 tpsvrinit(), tpsvrdone()에서 호출한다.
TMSNAME트랜잭션을 처리하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션을 처리한다. svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다.

데이터베이스 스크립트

다음은 Informix 테이블 생성 스크립트의 예제이다.

<mkdb.sql>

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

database stores7;
drop table ACCOUNT;

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

create unique index idx_tdb1 on ACCOUNT(account_id);
EOF

다음은 Informix 테이블 및 데이터 출력 스크립트의 예제이다.

<sel.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<client.c>

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

void htime(char *, int *);

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

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

       /*user가 원하는 수행 횟수만큼 루프를 돈다.*/
       loop = atoi(argv[1]);           

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

      /* sec1 = 시작시간 */
       htime(ts,&sec1); key=0;         

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

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

         if (tx_begin() < 0) { /* 트랜잭션 시작 */
              fprintf(stderr, “tx_begin() failed ->%s!\n”, tpstrerror(tperrno)) ;
              tpfree((char*)transf);
              tpend(); 
              exit(0);
         }

       /* select service 호출 */
       if (tpcall(“SEL_ACCT”, (char *)transf, 0, (char **)&transf, &nrecv, 
           TPNOFLAGS)== -1) {
           /* service error : message buffer free & 트랜잭션 취소 & 접속 끊음 */
            fprintf(stderr,“Tpcall(SELECT...)error->%s! ” ,
                      tpstrerror(tperrno)) ;
            tpfree ((char *)transf);
            tx_rollback ( ) ;
            tpend( ) ; 
            exit ( 1 ) ;
       }
       urcode = tpurcode;

      /*성공적인 서비스 완결 : 트랜잭션 결과로 실제 리소스 변화시킴*/
       if (tx_commit() < 0 ) {      
              fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ;
              tpfree((char *)transf); 
              tpend(); 
              exit(0);
       }

      /*데이터가 선택된 경우*/
      if ( urcode != NOTFOUND) { 
           narray =urcode;
           /* select한 데이터의 마지막 Record */
           key=transf[narray-1].ACCOUNT_ID;    
          /* selsct한 개수 만큼 결과를 user에게 출력 */  
          for ( j = 0 ; j < narray ; j++ ) {           
               if ( j == 0)
                   printf(“%-10s%-14s%s\n”, “ACCOUNT_ID”, “PHONE”,“ADDRESS”) ;
                   account_id = transf[j].ACCOUNT_ID;
                   strcpy(phone, transf[j].PHONE);
                   strcpy(address, transf[j].ADDRESS);
                   printf(“%-10d %-14s %s\n”, account_id, phone, address);
            }/* for2 end */

           /* 전체 결과 개수 증가 */
           cnt_data += j;        

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

       /* message buffer free */
       tpfree ((char *)transf);              
       /* Tmax 연결을 끊음. */ 
       tpend ();                         

       /* sec2 = 끝 시간 */ 
       htime(te,&sec2);            
       
       /* 데이터 하나당 처리시간 계산. */
       printf(“TOT.COUNT = %d\n”, cnt_data);     
       printf(“Start time = %s\n”, ts);
       printf(“End time = %s\n”, te);
      if ((sec2-sec1) ! = 0)
           tps = (float) cnt_data / (sec2 - sec1);
       else
           tps = cnt_data;
       printf(“Interval = %d secs ==> %10.2f T/S\n”, sec2-sec1,tps);
}

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

        pt = time(&timef);
        *sec = pt;
        tmp = localtime(&timef);
        ap = asctime(tmp);
 
        sscanf(ap, “%*s%*s%*s%s”,ct);
        sprintf( cdate, “%02d. %02d. %02d %s”, tmp->tm_year, ++tmp->tm_mon, 
                 tmp->tm_mday,ct);
} 

서버 프로그램

다음은 서버 프로그램의 예제이다.

<sel_acct.pc>

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

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

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

       /*클라이언트 데이터를 받는다. */
       ACCT_V = (struct stru_acct *) msg->data;  

       /* select원하는 account id 값을 key에 옮김. */
       key = ACCT_V->ACCOUNT_ID;           

       /* 클라이언트 버퍼 사이즈 재할당*/
       if ((ACCT_V = (struct stru_acct *)tprealloc((char *)ACCT_V, 
           sizeof(struct stru_acct)*NFETCH )) == (struct stru_acct *)NULL) { 
           fprintf(stderr, “tprealloc error =%s\n”, tpstrerror(tperrno));
           tpreturn (TPFAIL, tperrno, NULL, 0, TPNOFLAGS);
       }

       /*버퍼 초기화*/
       ACCT_V->ACCOUNT_ID = 0;          
       strcpy(ACCT_V->PHONE,“ ” ) ;
       strcpy(ACCT_V->ADDRESS,“ ” ) ;

       /* ACCOUNT 테이블로부터 phone, address 필드를 뽑음 */
       EXEC SQL declare CUR_1 cursor for
                 select account_id,phone,address
                  into :account_id, :pfone, :address
                  from ACCOUNT      
               where account_id > :key;/* 필드키보다 account id가 클 때 */

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

       nfetch=0 ;
       return_code = NOTFOUND;

       /* cursor open success */
       while (sqlca.sqlcode == 0) {         
           /* cursor서부터 data 하나씩 fetch */
           EXEC SQL fetch CUR_1;

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

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

            /* select한 데이터 개수 증가 */
            nfetch++;          
            return_code = nfetch

            /* NFETCH 개수만큼 select 했다면 while문 벗어남 */
           if (nfetch > NFETCH) {
               nfetch = NFETCH;
               return_code = nfetch;
               break ;
            }
       }
       /* cursor close */
       EXEC SQL close CUR_1;              

       /* select의 결과와 그 데이터를 클라이언트에게 리턴 */
       tpreturn ( TPSUCCESS, return_code, (char *)ACCT_V, 
                  sizeof(struct stru_acct)*nfetch, TPNOFLAGS);
}

5.4. 데이터베이스 연동 프로그램

애플리케이션을 개발할 때 응용하여 사용할 수 있는 예제를 통해 실제 프로그래밍의 기법을 설명한다. 데이터베이스 연동은 동일 기종 데이터베이스와 이기종 데이터베이스로 나뉜다.

5.4.1. 동기형 모드(동일 기종)

다음은 동기형 모드에서 동일 기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.

[그림 5.2] 동기형 모드 흐름도(동일 기종 데이터베이스)

동기형 모드 흐름도(동일 기종 데이터베이스)

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.sSDLFILE이다.
    sample.mTmax 환경파일이다.
    tmax.env환경파일이다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    update.pc, insert.pc서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

프로그램 특징

  • 클라언트 프로그램

    구분설명
    Tmax 연결NULL 파라미터로 연결
    버퍼 유형STRUCT
    하위 유형input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요
    트랜잭션 여부클라이언트에서 트랜잭션 지정
  • 서버 프로그램

    구분설명
    서비스 수UPDATE 서비스에서 INSERT 서비스 요청
    데이터베이스 연결Oracle 데이터베이스 사용 Tmax 환경파일의 SVRGROUP 절에 데이터베이스 정보 지정

프로그램 환경

구분설명
시스템SunOS 5.7 32bit
데이터베이스Oracle 8.0.5

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

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

Tmax 환경파일

다음은 Tmax 환경파일의 예제이다.

<sample.m>

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

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

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

*SERVER
update        SVGNAME=svg1
insert        SVGNAME=svg1

*SERVICE
UPDATE        SVRNAME=update
INSERT        SVRNAME=insert

다음은 환경파일의 예제이다.

<tmax.env>

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

데이터베이스 스크립트

다음은 데이터베이스 테이블을 생성하는 SQL 스크립트의 예제이다.

<mktable.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<client.c>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

서버 프로그램

다음은 데이터베이스에 UPDATE하는 서버 프로그램의 예제이다.

<update.pc>

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

#define OKMSG "YOU COMPLETE THE TRANSACTION"

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

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

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

다음은 데이터베이스에 INSERT하는 서버 프로그램의 예제이다.

< insert.pc>

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

#define OKMSG "YOU COMPLETE THE TRANSACTION"

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

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

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

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

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

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

5.4.2. 동기형 모드(이기종)

다음은 동기형 모드에서 이기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.

[그림 5.3] 동기형 모드 흐름도(이기종 데이터베이스 접속)

동기형 모드 흐름도(이기종 데이터베이스 접속)

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.sSDLFILE이다.
    sample.mTmax 환경파일이다.
    tmax.env환경파일이다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    구성설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    구성설명
    update.pc, insert.pc서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

참고

클라이언트와 서버프로그램 등 모두 “5.4.1. 동기형 모드(동일 기종)”의 경우와 같다. 멀티 노드 환경 설정에 대한 자세한 내용은 "Tmax Administration Guide"를 참고한다.

프로그램 특징

  • 클라이언트 프로그램

    구분설명
    Tmax 연결NULL 파라미터로 연결
    버퍼 유형STRUCT
    하위 유형input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요
    트랜잭션 여부클라이언트에서 명시적으로 트랜잭션 범위 지정
  • 서버 프로그램

    구분설명
    서비스 수UPDATE 서비스에서 INSERT 서비스를 요청
    데이터베이스 연결Oracle 데이터베이스를 사용하고 시스템 구성 파일의 SVRGROUP 절에 데이터베이스 정보 지정

프로그램 환경

구분설명
시스템SunOS 5.7 32bit, SunOS 5.8 32bit
데이터베이스Oracle 8.0.5

Tmax 환경파일

다음은 Tmax 환경파일의 예제이다.

<sample.m>

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

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

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

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

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

*SERVER
update      SVGNAME=svg1
insert      SVGNAME=svg2

*SERVICE
UPDATE      SVRNAME=update
INSERT      SVRNAME=insert

다음은 환경파일의 예제이다.

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

5.4.3. 비동기형 모드(동일 기종)

다음은 비동기형 모드에서 동일 기종데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.

[그림 5.4] 비동기형 모드 흐름도(동일 기종 데이터베이스 접속)

비동기형 모드 흐름도(동일 기종 데이터베이스 접속)


프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.sSDLFILE이다.
    sample.mTmax 환경파일이다.
    tmax.env환경파일이다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    update.pc서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile로 수정해야 한다.

프로그램 특징

  • 클라이언트 프로그램

    기능설명
    Tmax 연결NULL 파라미터로 연결
    버퍼 유형STRUCT
    하위 유형input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요
    트랜잭션 여부클라이언트에서 트랜잭션 지정
  • 서버 프로그램

    기능설명
    서비스 수UPDATE 서비스 요청
    데이터베이스 연결Orale 데이터베이스 사용하고 시스템 구성 파일의 SVRGROUP 절에 데이터베이스 정보 지정

프로그램 환경

구분설명
시스템SunOS 5.7 32bit
데이터베이스Oracle 8.0.5

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

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

Tmax 환경파일

다음은 Tmax 환경파일의 예제이다.

<sample.m>

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

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

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

*SERVER
update      SVGNAME=svg1

*SERVICE
UPDATE      SVRNAME=update

다음은 환경파일의 예제이다.

<tmax.env>

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

데이터베이스 스크립트

다음은 데이터베이스에 테이블을 생성하는 SQL 스크립트의 예제이다.

<mktable.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<client.c>

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

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

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

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

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

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

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

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

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

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

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

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

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

서버 프로그램

다음은 서버 프로그램의 예제이다.

<update.pc>

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

#define OKMSG "YOU COMPLETE THE TRANSACTION"

EXEC SQL include sqlca.h;

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

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

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

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

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

5.4.4. 대화형 모드(동일 기종)

다음은 대화형 모드에서 동일 기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.

[그림 5.5] 대화형 모드 흐름도(동일 기종 데이터베이스 접속)

대화형 모드 흐름도(동일 기종 데이터베이스 접속)

프로그램 구성

  • 공통 프로그램

    프로그램 파일설명
    demo.sSDLFILE이다.
    sample.mTmax 환경파일이다.
    tmax.env환경파일이다.
    mktable.sql데이터베이스에 테이블을 생성하는 SQL 스크립트이다.
  • 클라이언트 프로그램

    프로그램 파일설명
    client.c클라이언트 프로그램이다.
  • 서버 프로그램

    프로그램 파일설명
    update.pc서버 프로그램이다.
    MakefileTmax에서 제공되는 Makefile을 수정해야 한다.

프로그램 구성

  • 클라이언트 프로그램

    기능설명
    Tmax 연결NULL 파라미터로 연결
    버퍼 유형STRUCT
    하위 유형input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요 (애플리케이션을 실행시키기 위해 필요)
    트랜잭션 여부클라이언트에서 트랜잭션 지정
  • 서버 프로그램

    기능설명
    서비스 수UPDATE 서비스를 요청
    데이터베이스 연결Oracle 데이터베이스 지정하고 Tmax 환경파일의 SVRGROUP 절에 데이터베이스 정보 지정

프로그램 환경

구분설명
시스템SunOS 5.7 32bit
데이터베이스Oracle 8.0.5

구조체 버퍼

다음은 구조체 버퍼의 예제이다.

<demo.s>

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

Tmax 환경파일

다음은 Tmax 환경파일의 예제이다.

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


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

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

*SERVER
update      SVGNAME=svg1, CONV=YES

*SERVICE
UPDATE      SVRNAME= update

다음은 환경파일의 예제이다.

<tmax.env>

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

데이터베이스 스크립트

다음은 데이터베이스에 테이블을 생성하는 SQL 스크립트의 예제이다.

<mktable.sql>

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

클라이언트 프로그램

다음은 클라이언트 프로그램의 예제이다.

<client.c>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

서버 프로그램

다음은 서버 프로그램의 예제이다.

<update.pc>

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

void _db_work();

#define OKMSG "YOU COMPLETE THE TRANSACTION"

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

struct input *rcvbuf;

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

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

        count = 1;
        flag = 0;

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

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

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

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

            count++;
        }

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

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

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

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

5.5. TIP를 이용한 프로그램

Tmax에서는 TIP(Tmax Information Provider)를 사용하여 시스템 환경 정보, 통계 정보 확인, 시스템 운용 관리 등 다양한 기능을 수행할 수 있다. TIP은 TIPSVC를 처리하기 위하여 Tmax에서 제공하는 기능 프로세스로, TIP을 사용하여 다음의 기능을 수행할 수 있다.

  • 시스템 환경 정보 확인: 시스템의 정적인 환경 정보를 확인한다.

  • 시스템 통계 정보 확인: 시스템 운영 중에 각각 프로세스의 상태 등을 확인한다.

  • 시스템 운용 관리: 프로세스를 추가로 기동하거나 종료한다.

5.5.1. TIP 구조

TIPSVC를 처리하기 위한 별도의 기능 프로세스인 TIP 서버는 SYS_SVR 서버 타입을 가지며, TIP 서버 그룹에 속한다. 클라이언트 혹은 서버의 요청을 받은 TIP 서버는 그 요청을 CLH/TMM에게 전달하여 처리 결과를 다시 요청자에게 돌려준다. TIP 서버는 필드 키를 바탕으로 서비스를 처리한다. 요청하는 클라이언트나 서버는 필드 버퍼에 요구하려는 데이터를 실어 요청을 하며, 그 결과를 필드 버퍼로 받는다.

  • CHLOG section (로그 레벨 변경)

    CHLOG는 TMM, CLH, TMS, SVR 의 log level을 변경할 수 있는 섹션이다. tmadmin 에서 chlog를 실행하는 것과 동일한 동작을 수행한다.

    TIP 서비스를 호출할 경우, 필드 버퍼에 아래를 설정하여 TIPSVC를 호출한다.

    항목설명
    TIP_OPERATION (string)GET으로 설정한다.
    TIP_SEGMENT (string)ADMINISTRATION으로 설정한다.
    TIP_SECTION (string)CHLOG로 설정한다.
    TIP_MODULE (int)

    동적으로 로그를 변경하고 싶은 모듈을 설정하는 항목으로 다음 중 하나를 선택한다.

    TIP_TMM | TIP_CLH | TIP_TMS | TIP_SVR

    TIP_FLAGS (int)

    flags를 설정하는 항목으로 다음 중 하나를 선택한다.

    TIP_VFLAG | TIP_GFLGA | TIP_NFLAG

    TIP_SVRNAME (string)해당 서버명을 설정하는 항목으로 TIP_FLAGS를 TIP_VFLAG로 설정한 경우에만 설정한다.
    TIP_SVGNAME (string)해당 서버 그룹명을 설정하는 항목으로 TIP_FLAGS를 TIP_GFLAG로 설정한 경우에만 설정한다.
    TIP_NODENAME (string)해당 노드명으로 TIP_FLAGS를 TIP_NFLAG로 설정한 경우에만 설정한다.
    TIP_LOGLVL (string)

    변경하고자 하는 로그 레벨을 설정하는 항목으로 다음 중에 하나를 선택하고 반드시 소문자로 설정한다. 결과로 받아오는 값은 TIP_ERROR에 설정된다.

    compact | basic | detail | debug1 | debug2 | debug3 | debug4

    TIP_ERROR (int)

    에러값이 설정되는 항목으로 설정되는 에러값은 다음과 같다.

    • TIPESVCFAIL: 해당 서비스를 제대로 처리하지 못한 경우

    • TIPEOS: 메모리 할당에 실패한 경우

    • TIPEBADFLD: TIP_MODULE 값을 설정하지 않은 경우

  • CHTRC section

    TMS와 SPR의 TMAX_TRACE를 수정하여 trace log 옵션을 변경할 수 있는 섹션이다. tmadmin의 chtrc와 동일한 동작을 수행한다.

    TIP 서비스를 호출할 경우, 필드 버퍼에 아래를 설정하여 TIPSVC를 호출한다.

    항목설명
    TIP_OPERATION (string)GET으로 설정해야 한다.
    TIP_SEGMENT (string)ADMINISTRATION으로 설정해야 한다.
    TIP_SECTION (string)CHTRC로 설정해야 한다.
    TIP_FLAGS (int)

    flags를 설정하는 항목으로 다음 중에 하나를 설정한다.

    TIP_PFLAG| TIP_VFLAG | TIP_GFLAG | TIP_NFLAG

    TIP_SPRI (int)spri를 설정하는 항목으로 TIP_FLAGS를 TIP_PFLAG로 설정한 경우에만 설정한다.
    TIP_SVGNAME (string)해당 서버 그룹명을 설정하는 항목으로 TIP_FLAGS를 TIP_GFLAG로 설정한 경우에만 설정한다.
    TIP_NODENAME (string)해당 노드명을 설정하는 항목으로 TIP_FLAGS를 TIP_NFLAG로 설정한 경우에만 설정한다.
    TIP_SPEC (string)변경하고자 하는 filter spec, receiver spec, trigger spec을 설정하는 항목이다. 결과로 받아오는 값은 TIP_ERROR에 설정된다.
    TIP_ERROR (int)

    에러값이 설정된다. 설정되는 에러값은 다음과 같다.

    • TIPESVCFAIL : 해당 서비스를 제대로 처리하지 못한 경우

    • TIPEOS : 메모리 할당에 실패한 경우

    • TIPEBADFLD : TIP_MODULE 값을 설정하지 않은 경우

다음은 TIPSVC에 요청하기 위하여 포함해야 할 데이터이다.

  • 조직(TIP_OPERATION)

    설정값설명
    GET시스템의 정적인 환경 정보, 통계 정보의 확인, BOOT/DOWN 시스템 운용 관리할 경우에는 GET으로 설정한다.
    SET시스템 설정 상태를 변경하려고 하는 경우에 SET으로 설정한다. 현재는 GET만 사용된다.
  • 세그먼트(TIP_SEGMENT)

    어떤 기능을 수행할지 결정하기 위하여 사용하는 필드로 다음은 TIP_SEGMENT 필드에 설정할 수 있는 값이다.

    설정값설명
    CONFIGURATION시스템의 정적인 설정 정보를 확인한다.
    STATISTICS시스템의 운영 중에 통계 정보를 확인한다.
    ADMINISTRATION시스템 운용 관리(BOOT/DOWN)를 확인한다.

  • 절(TIP_SECTION)

    TIP_SECTION을 설정했을 경우 어떤 항목에 대하여 처리를 할 것인지 세부 항목을 결정한다.

    설정값설명
    CONFIGURATIONDOMAIN, NODE, SVRGROUP, SERVER, SERVICE, ROUTING, RQ, GATEWAY
    STATISTICSNODE, SPR, SERVICE, RQ
    ADMINISTRATIONBOOT, DOWN, CHLOG, CHTRC

  • 명령어(TIP_CMD)

    필드는 TIP_SECTION이 ADMINISTRATION일 경우에만 사용된다.

    설정값설명
    TIP_BOOTTmax 시스템을 기동한다.
    TIP_DOWNTmax 시스템을 종료한다.

5.5.2. TIP 사용

TIP의 사용 방법과 에러 확인하는 방법에 대해 설명한다.

TIP 사용 방법

  • 환경 설정

    TIP 서버는 Tmax에서 제공하는 기능 프로세스이기 때문에 사용자가 서비스를 작성할 필요가 없다. 단, 환경파일에 TIP 서버를 등록해야 한다. 다음은 환경 설정의 예제이다.

    *DOMAIN
    res             ..., TIPSVC = TIPSVC
    
    *NODE
    tmaxs1       ...
    
    *SVRGROUP
    tsvg            ..., SVGTYPE = TIP
    
    *SERVER
    TIP             SVGNAME = tsvg, SVRTYPE = SYS_SVR
    • DOMAIN 절에는 TIPSVC를 등록한다. 등록하지 않을 경우에는 기본값으로 TIPSVC가 등록된다.

    • SVRGROUP 절에는 TIP 서버 그룹(SVGTYPE=TIP)을 등록한다.

    • SERVER 절에는 TIP 서버(SVRTYPE=SYS_SVR)를 등록한다.

      참고

      Tmax v5.0 SP2 Fix#1부터 TIP 서버의 MIN, MAX 설정을 1 이상으로 설정할 수 있다. 따라서 여러 개의 TIP 서버가 기동되어 TIPSVC 요청들을 동시에 처리할 수 있다.

  • 시스템 접속

    사용자는 Tmax 시스템 접속할 때에 TPSTART_T 구조체의 usrname 항목에 .tpadmin을 설정해야 한다. TIP_SEGMENT가 ADMINISTRATION일 경우에만 usrname을 설정하며, 다른 경우에는 설정하지 않아도 된다. 잘못된 usrname이 설정되었을 경우에는 TIP_ERROR 필드에 TIPEAUTH 에러가 설정된다.

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

  • 버퍼 할당

    TIP 서버는 필드키를 바탕으로 서비스를 처리하므로 요청하는 클라이언트나 서버 프로그램은 필드키 버퍼를 할당해야 한다.

  • TIP 요청 항목 설정

    항목설명
    TIP_OPERATION시스템 환경정보 변경 및 확인할 경우 설정한다.
    TIP_SEGMENT시스템 정보확인 및 운영관리를 위해서 설정한다.
    TIP_SECTIONSEGMENT에서 설정항목에 대한 세부처리를 설정한다.
    TIP_CMDTIP_SEGMENT가 ADMINISTRATION일 경우만 설정한다.
    TIP_NODENAME멀티 노드일 경우만 설정하며, 단일 노드일 경우 지정하지 않으면 기본값으로 로컬 노드가 설정된다. 잘못 설정하였을 경우 TPEINVAL 에러가 발생한다.
  • TIPSVC 요청

    TIP 요청 항목을 설정하였다면 설정한 필드 버퍼를 sndbuf로 하여, tpcall이나 tpacall을 이용하여 TIPSVC로 요청을 한다. 클라이언트, 서버에서 모두 요청할 수 있으며, 트랜잭션은 지원하지 않는다.

  • 결과 수신

    수신 필드키 버퍼에 서비스 결과가 저장된다.

에러 확인

  • 정상 처리된 경우

    수신 필드키 버퍼의 TIP_ERROR 항목에 0이 설정된다.

  • 에러가 발생한 경우

    에러설명
    TIP_STATUSTIP_ERROR에 설정된 에러 내용에 대하여 상세한 에러 내용을 확인할 수 있다.
    TIP_BADFIELD에러를 유발시킨 필드를 확인할 수 있다.
    TIP_ERROR수신 필드키 버퍼의 TIP_ERROR 항목에 0보다 큰 값이 설정된다. 이는 /usrinc/tip.h에서 확인할 수 있다.

    다음은 TIP_ERROR에 설정되는 에러값에 대한 설명이다.

    설정값설명
    TIPNOERROR에러가 발생하지 않는다.
    TIPEBADFLD유효하지 않은 필드키가 사용되었다. 일반적으로 fdlc 유틸리티를 사용하여 컴파일되지 않은 필드키가 사용되었을 경우 TIP_ERROR는 TIPEBADFLD로 설정된다.
    TIPEIMPL구현되지 않은 기능에 대하여 요청한 경우이다.
    TIPEAUTH현재의 권한으로는 허용되지 않는 서비스이다.
    TIPEOS운영 시스템 또는 시스템 에러로서 메모리 할당 실패, Tmax 시스템에 접속 실패, 또는 네트워크 상태가 불안정할 경우 등에 나타나는 에러이다.
    TIPENOENT존재하지 않는 항목을 접근하는 경우에 발생한다.
    TIPESVCFAILTIP 서비스 루틴이 에러가 발생하여 TPFAIL로 tpreturn()을 호출하였다.

5.5.3. TIP 사용 예제

본 절은 TIP를 사용한 예제를 설명한다.

환경파일

다음은 단일 노드를 사용한 예제이다.

<cfg.m>

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

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

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

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

*SERVICE
TOUPPER        SVRNAME=svr

다음은 멀티 노드를 사용한 예제이다.

<cfg.m>

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


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

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

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

svg1          NODENAME = "tmaxh4", COUSIN = "svg2"
svg2          NODENAME = "tmaxh2"


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

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

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

필드키 테이블

다음은 필드키 테이블의 예제이다.

< tip.f >

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

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

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


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

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


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

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


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


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

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


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

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

#
#       EXTRA flag fields
#
# name               number     type    flags   comments
*base 16000700
TIP_EXTRA_OPTION        0       int

5.5.4. 시스템 환경 정보 조회 프로그램

다음은 시스템의 환경 정보를 확인하는 클라이언트 프로그램의 예제이다.

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

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

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

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

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

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

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

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

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

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

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

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

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

        n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf,  &rcvlen, 
                    TPNOFLAGS);

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

#if 1
        fbprint(rcvbuf);
#endif

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

[결과]

다음은 해당 프로그램의 결과(Domain Conf)이다.

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

5.5.5. 시스템 통계 정보 조회 프로그램

다음은 시스템의 통계 정보를 확인하는 프로그램의 예제이다.

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

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

#define NODE_NAME_SIZE 32

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

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

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

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

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

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

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

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

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

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

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

        fbprint(rcvbuf);

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

[결과]

다음은 해당 프로그램의 결과(TMS STATISTICS)를 나타내는 예제이다.

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

5.5.6. 서버 프로세스 기동 및 종료 프로그램

예제1

다음은 서버 프로세스를 추가로 기동하거나 종료하는 프로그램 예제이다.

< cli.c >

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

#define NODE_NAME_SIZE  32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        fbprint(rcvbuf);

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

예제2

다음은 svr23_stat_ins 이라는 서버의 log level을 debug4로 변경하는 예제이다.

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

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

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

#define NODE_NAME_SIZE  32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[결과] (TIP_SVR, => DEBUG4)

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

         loglvl = DEBUG4

5.6. Local recursive call

서버에서 tpcall()을 수행할 경우 같은 서버에 존재하는 서비스일 경우에도 내부에서 Recursive하게 호출할 수 있도록 기능이 추가되었다. 이는 서버에서 Multicontext 기법을 통해 tpcall()에 한해서 Local Recursive call이 가능하도록 한 것으로, 무한 loop를 방지하기 위해서 최대 depth는 8로 제한한다.

주의

Local Recursive call을 사용하기 위해서는 서버 프로그램을 컴파일할 때 반드시 CFLAGS에 –D_MCONTEXT를 추가해야 하며, libsvr.so 대신 libsvrmc.so 서버 라이브러리를 이용해 컴파일해야 한다.

서버 프로그램

다음은 서버 프로그램의 예제이다.

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


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

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

         strcat(rcvbuf, "_Success");

         tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0);
}

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

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

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

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

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

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

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

Makefile

다음은 Makefile의 예제이다.

<Makefile.c.mc>

# Server makefile

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

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

SVCTOBJ = $(TARGET)_svctab.o

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

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

#
.SUFFIXES : .c

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

#
# server compile
#

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

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

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

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