반응형

 

Pro-C 간단 매뉴얼

---------------
  2000. 5. 23
---------------

+++++++++++
  ProC...
+++++++++++

-. 오라클 데이타베이스 테이블에 존재하는 레코드 조회,수정 등 데이타 처리를 하고, C 프로그램으로 전환/연동함.

-. C 언어와 차이점
        -. 외형 차이 : 확장자가 *.pc
        -. 기본 C 문법을 따르며, C 프로그램 코드에 DB 접속 레코드 처리 과정 등이 추가 작성
           즉, C 프로그램 코드에 오라클 SQL의 DML or DDL 명령문이 'EXEC' 구문과 결합된 형태로 추가
        -. 변수 선언에 C 언어에 없는 .arr과 .len이라는 변수가 컴파일된 C 소스 코드에 생성됨

-. 컴파일 과정
        -. filename.pc -> filename.c -> filename.o -> filename* (오브젝트 파일을 링크하여 실행 파일 생성)
       
-. 실제 컴파일
        -. makefile 위치
        $ORACLE_HOME에 proc/에 보면 proc.mk 파일이 있다.
       
        이중에서
        1) USERID = uinfo/mation
         -. 오라클 DB 접속용 사용자 아이디와 비밀번호 지정
        
        2) DEST = /home/elfsun/simple/bin
        -. 컴파일 후 실행파일을 복사할 디렉터리
       
        3) COMM_OBJ = /home/elfsun/simple/lib/lib1.o\
                      /home/elfsun/simple/lib/lib2.o\
                      /home/elfsun/simple/lib/lib3.o\
                      /home/elfsun/simple/lib/lib4.o
        -. 컴파일시 참조할 오브젝트 파일들이다.  \(백슬레시)로 구분함.
       
        4) all : $(PROGRAM)
        -. 프로그램 이름을 지정한다. 프로그램 소스 이름이면서, 컴파일 후 생성되는 실행 파일 이름이다.
       
        5) install :
        -. 컴파일후 생성된 실행 파일을 복사해주는 작업 수행
       
        6) clean :
        -. 컴파일 과정에서 생성되는 임시 C 파일과 오브젝트 파일을 삭제할 때 수행
       
        이들중 수행할 각 명령은 '@' 뒤에 작성할 수 있다.
       
        [실제 컴파일 수행 - makefile 이름이 proc.mk인 경우]
       
        1) 컴파일을 하기 위해
                $ make -f proc.mk
       
        2) 컴파일한 실행 파일을 ~/bin/ 디렉토리에 복사
                $ make -f proc.mk install
       
        3) 컴파일 후 생성되는 오브젝트 파일과 c 파일을 삭제
                $ make -f proc.mk clean
               
-. SQLCA 관련 변수들.
        -. sqlca.sqlerr[0] : fetch를 사용하여 쿼리된 레코드 건수를 리턴시켜 주는 변수
        -. sqlca.sqlwarn : 경고에 대한 정보가 담긴 변수
        -. sqlca.sqlerrm.sqlerrmc : sql 명령 수행 에러가 발생했을때, 에러 내용과 오류 코드 정보를 출력
           ---------------------------------------
        -. sqlca.sqlcode값        내 용
           ---------------------------------------
           0               sql문 정상 수행
          
           1403          유일하게 양수값을 갖는 에러 코드이다.
                           조건에 맞는 데이타가 하나도 없을 때 발생.
          
           -1405        조회된 값에 null 값이 있을 때
           ---------------------------------------


-. host 변수 선언
       
        -. 호스트 변수는 데이타베이스에서 데이타 처리 결과를 저장하기 위해 사용되며,
        응용 프로그램내에서는 변수 역할을 한다. 따라서 호스트 변수를 선언할 때에는
        데이타베이스 내에서 사용되는 칼럼의 데이타 타입과 그 크기를 고려하여 선언해야 하며,
        프리컴파일 과정을 통해 응용프로그램내에서도 사용 가능한 형태이어야 한다.

        ex)
        EXEC SQL BEGIN DECLARE SECTION;
                varchar username[16], userarea[10];
                int usrno, usrage;
        EXEC SQL END DECLARE SECTION;          
       
        [주의]        
        1) 호스트 변수 선언 시 오라클 예약어 사용 금지
        2) 호스트 변수에서 null 처리를 해주지 않기에 응용프로그램에서 null 처리를 해야 한다.
           단, 호스트 변수가 숫자형인 경우는 예외이다.
          

-. DB 접속

        방법1>
        EXEC SQL CONNECT elfsun
                INDENTIFIED BY 1234;
               
        방법2>
        EXEC SQL BEGIN DECLARE SECTION;
                varchar userid[8], passwd[8];
        EXEC SQL END DECALRE SECTION;          
       
        strncpy(userid.arr,"elfsun",6);
        strncpy(passwd.arr,"1234",4);
       
        EXEC SQL CONNECT :userid;
                IDENTIFIED BY :passwd;
       
        -. 일반적으로 방법2를 선호함.
        -. 방법2를 쓸때, 변수명 앞에 ':'를 붙여서 그 변수가 호스트 변수임을 명시해야 한다.
       

-. CURSOR 이용 : 쿼리문으로 조회되는 레코드가 한 건 이상일때 사용함.

        형식>        
        1) EXEC SQL PREPARE statement FROM variable;  (쿼리하고자 하는 sql 문장 정의)
        2) EXEC SQL DECLARE cursor_name CURSOR FOR statement; ( 사용할 커서 선언 )
        3) EXEC SQL OPEN cursor_name;   ( 선언한 커서 열기 )        
        4) EXEC SQL FETCH cursor_name INTO :host_variable1, :host_variable2, :host_variable3, ....;  (연 커서 실행)
        5) EXEC SQL CLOSE cursor_name;  ( 열었던 커서 닫음 )
       

        1) EXEC SQL PREPARE statement FROM variable;  (쿼리하는 sql 문장 정의)
                ex)
                char SqlCmd[100];    (변수 SqlCmd를 선언)
                memset(SqlCmd,0x00,sizeof(SqlCmd));  ( memset함수를 이용하여 초기화 작업함)
                sprintf(SqlCmd,"SELECT usrno, usrname, usrarea FROM forumlist");  (쿼리문을 SqlCmd에 대입)
                EXEC SQL PREPARE st_1 from :SqlCmd; (EXEC..문장을 이용하여 쿼리할 구조를 정의함)

        2) EXEC SQL DECLARE cursor_name CURSOR FOR statement; ( 사용할 커서 선언 )
                형식1>
                EXEC SQL DECLARE cursor_name CURSOR FOR statement;
                형식2>
                EXEC SQL DECLARE cursor_name CURSOR FOR select 문장;
               
                -. cursor_name : 사용할 커서명
                ex)
                EXEC SQL DECLARE CUR_1 CURSOR FOR ST_1; (ST_1은 PREPARE에서 정의한것과 동일해야 함)
                EXEC SQL DECLARE CUR_1 CURSOR FOR select usrno, username, userarea From forumlist;

        3) EXEC SQL OPEN cursor_name;   ( 선언한 커서 열기 )
                ex)
                EXEC SQL OPEN CUR_1;
               
        4) EXEC SQL FETCH cursor_name INTO :host_variable1, :host_variable2, :host_variable3, ....;  (연 커서 실행)
                ex)
                EXEC SQL BEGIN DECLARE SECTION;
                        varchar usrname[16], usrarea[10];
                        int usrno;
                EXEC SQL END DECLARE SECTION;
                        ......
                       
                EXEC SQL FETCH CUR_1 INTO :usrno, :usrname, :userarea;
               
                -. 여기서 사용하는 조회된 칼럼들과 1대1로 대응되어야 한다.
                또한 사용될 호스트 변수들은 이미 이전에 선언되어 있어야 사용 가능하다.
                칼럼의 데이타 타입과 크기가 일치해야 함에도 주의.

        5) EXEC SQL CLOSE cursor_name;  ( 열었던 커서 닫음 )
                ex)
                EXEC SQL CLOSE CUR_1;


-. 오류 처리

        1) whenever sqlerror 구문
                형식)
                ① EXEC SQL WHENEVER SQLERROR GOTO stop_st;
               
                ② EXEC SQL WHENEVER SQLERROR GOTO STOP;
               
                ③ EXEC SQL WHENEVER SQLERROR GOTO CONTINUE;
                       
                -. 위 문장들은 SQL 문장의 수행 결과 리턴되는 sqlca.sqlcode 값이 음수로,
                에러를 발생하는 경우, 더이상 프로그램을 진행시키지 않도록
                stop_st 루틴(①번 해당)으로 분기하여 프로그램 에러처리를 하도록 하는 문장임.
                stop_st대신 STOP나 CONTINUE를 쓰기도 한다.
               
                -. 또한 실행시켰던 SQL 문장들이 레코드 값 자체 변경과 관련이 있는 문장,
                즉 INSERT, DELETE, UPDATE 같은 SQL 문장들이었다면,
                'EXEC SQL ROLLBACK WORK' 명령으로 그 트렌잭션 취소 과정을 추가해야 한다.
               
        2) whenever not found 구문
                형식)
                EXEC SQL WHENEVER NOT FOUND GOTO stop_st;
               
                EXEC SQL WHENEVER NOT FOUND STOP;
               
                EXEC SQL WHENEVER NOT FOUND CONTINUE;
               
                -. 위 문장들은 SQL 문장 실행 결과 sqlca.sqlcode 값이 1403으로,
                조건에 맞는 레코드 건수가 하나도 없는 경우이다.
               

-. ProC내에서의 select 문장
        ex1)
        -------------------------------------------------------------
        EXEC SQL BEGIN DECALRE SECTION;
                varchar usrname[16], usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;
       
        EXEC SQL SELECT usrno, usrname, usrarea
                INTO : usro, :usrname, :usrarea
                FROM forumlist
                WHERE usrno=5;
       
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        EXEC SQL COMMIT WORK;
       
        printf("\n 회원의 고유번호        =%d",usrno);
        printf("\n 회원의 이름                =%d",usrname.arr);
        printf("\n 회원의 이름(크기)        =%d BYTE", usrname.len);
        printf("\n 회원의 거주지역        =%s", usrarea.arr);
        printf("\n 회원의 거주지역(크기) =%d BYTE", usrarea.len);
       
        stop_st :
        printf("\n 에러메시지 =%s", sqlca.sqlerrm.sqlerrmc);
        -------------------------------------------------------------
        -. into 구문은 쿼리 결과에 만족하는 데이타를 검색해 와서 into구문 뒤의 변수에 각각 할당한다.
        -. 호스트 변수명 앞에 (:)을 붙여 줌으로써 조회할 테이블이 칼럼명과 구분을 지어 준다.
       
        ex2)
        -------------------------------------------------------------
        EXEC SQL BEGIN DECALRE SECTION;
                varchar usrname[16], usrarea[10];
                int usrno;
                char SqlCmdp100];
        EXEC SQL END DECLARE SECTION;
       
        memset(SqlCmd,0x00,sizeof(SqlCmd));
        sprintf(Sqlcmd,"select usrno, usrname, usrarea from forumlist");
        EXEC SQL PREPARE ST_1 FROM :SqlCmd;
        EXEC SQL DECLARE CUR_1 FOR ST_1;
        EXEC SQL OPEN CUR_1;
        EXEC SQL FETCH SUR_1 INTO :usrno, :usrname, :usrarea;

        if (sqlca.sqlcode < && sqlca.sqlcode != -1405)
        {
                printf("\n 에러메시지 = %s", sqlca.sqlerrm.sqlerrmc);
                printf("\n 레코드 조회시 에러 발생!");
                EXEC SQL CLOSE CUR_1;
                EXEC SQL ROLLBACK WORK;
                exit();
        } /* error */
        else if(sqlca.sqlcode == 1403)
        {
                printf("\n 에러메시지 ="%s", sqlca.sqlerrm.sqlerrmc);
                printf('\n 조건에 맞는 데이타가 없슴다!");
                EXEC SQL CLOSE CUR_1;
                EXEC SQL ROLLBACK WORK;
                exit();
        } /* not exist */
        while(sqlca.sqlcode ==0)
        {
                printf("\n 회원의 고유번호        =%d",usrno);
                printf("\n 회원의 이름                =%d",usrname.arr);
                printf("\n 회원의 이름(크기)        =%d BYTE",usrname.len);
                printf("\n 회원의 거주지역        =%s", usrarea.arr);
                printf("\n 회원의 거주지역(크기) =%d BYTE", usrarea.len);
                EXEC SQL FETCH CUR_1 INTO :usrno, :usrname, :usrarea;
        } /* while */
        printf("\n 오라클 메시지 = %s",sqlca.sqlerrm.sqlerrmc);
        printf("\n 레코드가 성공적으로 조회되었습니다.");
        EXEC SQL CLOSE CUR_1;
        EXEC SQL COMMIT WORK;
        -------------------------------------------------------------
       
-. PROC속의 UPDATE문장
        -----------------------------------------------------------------------------
        ex1)
        EXEC SQL BEGIN DECLARE SECTION;
                varchar username[16], usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;        
       
        EXEC SQL SELECT usrno, username, usrarea
                into :usrno, :usrname, :usrarea
                from forumlist
                where usrno=3;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n 변경전 회원[%d]번의 거주지역 =[%s]",usrno,usrarea.arr);
        EXEC SQL COMMIT WORK;
        strcpy(userarea.arr,"SEOUL");
        usrarea.len =5;
       
        EXEC SQL UPDATE FORUMLIST
                SET usrarea =:usrarea
                WHERE usrno =3;
       
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        EXEC SQL COMMIT WORK;
        printf("\n 오라클 메시지 =%s",sqlca.sqlerrm.sqlerrmc);
       
        EXEC SQL SELECT usrno,usrarea
                INTO :usrno, :usrarea
                FROM forumlist
                WHERE usrno=3;
       
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n 변경후의 회원 [%d]번의 거주지역 =[%s]", usrno.usrarea.arr);
        EXEC SQL COMMIT WORK;
        exit();
       
        stop_st:
        EXEC SQL ROLLBACK WORK;
        printf("\n 에러발생 =%s",sqlca.sqlerrm.sqlerrmc);
        -----------------------------------------------------------------------------
       
        -----------------------------------------------------------------------------
        ex2)
        EXEC SQL BEGIN DECLARE SECTION;
                varchar usrname[16], usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;
        char SqlCmd[100];
       
        EXEC SQL select usrno,username,usrarea
                into :usrno, :usrname, :usrarea
                from forumlist
                where usrno=3;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n 변경전의 [%d]번째 회원의 거주지역 =[%s]", usrno, usrarea.arr);
        EXEC SQL COMMIT WORK;
       
        memset(SqlCmd,0x00,sizeof(SqlCmd));
        sprintf(SqlCmd,"UPDATE FORUMLIST set usrarea=%s \  (문장이 끝나지 않아서 \(역슬래시) 사용)
                                where usrno=3","seoul");
        EXEC SQL EXCUTE IMMEDIATE :SqlCmd;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
        EXEC SQL COMMIT WORK;
       
        EXEC SQL select usrno, usrarea
                into :usrno, :usrarea
                from forumlist
                where usrno=3;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n 변경후의 [%d]번째 회원의 거주지역 =[%s]", usrno,usrarea.arr);
        EXEC SQL COMMIT WORK;
        exit();
       
        stop_st:
        EXEC SQL ROLLBACK WORK;
        printf("\n 에러 메시지 =%s", sqlca.sqlerrm.sqlerrmc);
        -----------------------------------------------------------------------------
        -. 위 update 문을 약간 수정하면
        sprintf(SqlCmd,"update forumlist set userarea=%s where usrno=%d","seoul",3);


-. ProC 속의 Insert 문장
        -----------------------------------------------------------------------------
        ex1)
        EXEC SQL BEGIN DECLARE SECTION;
                varchar usrname[16], usrarea[10], usrkindcode[4];
                int usrno ;
        EXEC SQL END DECLARE SECTION;
        int tot;
       
        tot =0;
        usrno=10;
        strncpy(usrname.arr,"LEE-Y-S",Strlen("LEE-Y-S"));
        strncpy(usrarea.arr,"seoul",strlen("seoul"));
        strncpy(usrkindcode,"1004",strlen("1004"));
       
        EXEC SQL INSERT INTO FORUMLIST(usrno, usrname, usrarea, usrkindcode)
                values(:usrno, :usrname, :usrarea, :usrkindcode);
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
        printf("\n insert success!!");
        printf("\n 오라클 메시지 = %s", sqlca.sqlerrm.sqlerrmc);
       
        EXEC SQL SELECT COUNT(*)
                INTO :TOT
                FROM FORUMLIST
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n forumlist 테이블에 존재하는 총 회원 수 =%d", tot);
        EXEC SQL COMMIT WORK;
       
        EXEC SQL SELECT usrno, usrarea
                INTO :usrno, :usrarea
                FROM FORUMLIST
                WHERE usrno=10;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n 추가된 회원 [%d]번의 거주지역 =[%s]", usrno, usrarea.arr);
        EXEC SQL COMMIT WORK;
       
        stop_st;
        EXEC SQL ROLLBACK WORK;
        printf("\n 오라클 에러=%d",sqlca.sqlerrm.sqlerrmc);
        -----------------------------------------------------------------------------
        ex1은 insert문장에 함께 기술해 줄 호스트 변수들을 선언해 주었지만...
        ex2에서는 선언하지 않았다.
        ex2의 첨에 있는 usrarea는 그 다음에 수행할 select명령에 필요한 선언 문장이다.
        -----------------------------------------------------------------------------
        ex2)
        EXEC SQL BEGIN DECLEARE SECTION;
                varchar usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;
        char SqlCmd[100];
        int tot;
       
        tot=0;
        memset(SqlCmd,0x00,sizeof(SqlCmd));
        sprintf(SqlCmd,"insert into forumlist(usrno, usrname, usrarea, \
                        usrkindcode) values(%d, %s, %s, %s)", \
                        10,"lee-k-y","seoul","1004");
        EXEC SQL EXECUTE IMMEDIATE :SqlCmd;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n Insert Success!");
       
        EXEC SQL SELECT count(*)
                into :tot;
                from forumlist
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n forumlist 테이블에 존재하는 총 회원 수 = %d",tot);
        EXEC SQL COMMIT WORK;
       
        EXEC SQL SELECT usrno, usrarea
                into :usrno, :usrarea
                from forumlist
                where usrno=10;
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
        printf("\ 추가된 회원 [%d]번의 거주지역 =[%s]",usrarea.arr);
        EXEC SQL COMMIT WORK;
       
        stop_st:
        EXEC SQL ROLLBACK WORK;
        printf("\n 오라클 에러 = %d", sqlca.sqlerrm,sqlerrmc);
        -----------------------------------------------------------------------------

-. Proc내에서의 delete문장.

        -----------------------------------------------------------------------------
        ex1)
        EXEC SQL BEGIGN DECLRAE SECTION;
                varchar usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;
        int tot;
       
        tot=0;
        EXEC SQL DELETE FORUMLIST WHERE USRNO=10;
       
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
        EXEC SQL COMMIT WORK;
       
        printf("\n Delete 문장 성공!!");
       
        EXEC SQL SELECT count(*)
                into :tot;
                from forumlist
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n forumlist 테이블에 존재하는 총 회원 수 =%d",tot);
        EXEC SQL COMMIT WORK;
       
        stop_st:
        EXEC SQL ROLLBACK WORK;
        printf("\n Oracle Error =%d",sqlca.sqlerrm.sqlerrmc);
        -----------------------------------------------------------------------------
        -. 어떠한 호스트 변수도 사용하지 않음.
       
        -----------------------------------------------------------------------------
        ex2)
        EXEC SQL BEGIN DECLARE SECTION;
                varchar usrarea[10];
                int usrno;
        EXEC SQL END DECLARE SECTION;
        char SqlCmd[100];
        int tot;
        tot=0;
        memset(SqlCmd,0x00,sizeof(SqlCmd));
        sprintf(SqlCmd,"Delete forumlist where usrno=%d",10);
        EXEC SQL EXCUTE IMMEDIATE :SqlCmd;
       
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
        EXEC SQL COMMIT WORK;
       
        prinf("\n Delete Success!!");
       
        EXEC SQL SELECT COUNT(*)
                INTO :TOT;
                FROM FORUMLIST
        EXEC SQL WHENEVER SQLERROR GOTO stop_st;
       
        printf("\n forumlist 테이블에 존재하는 총 회원 수=%d",tot);
        EXEC SQL COMMIT WORK;
       
        stop_st;
        EXEC SQL ROLLBACK WORK;
        printf("\n Oracle Error : =%d",sqlca.sqlerrm.sqlerrmc);
        -----------------------------------------------------------------------------
        -. where절에서 회원의 고유번호값을 지정해주었다.는 점이 ex1과 다른점이다.
        -. delete 부분을 다음과 같이 수정해도 된다.
                usrnum=10;
                sqlprintf(SqlCmd,"delete forumlist where usrno=%d",usrnum);
                이처럼 변수를 먼저 선언해준 후 값을 대입해서 삭제 하는 방법도 있다.


-. 트랜잭션의 제어
       
        -. EXEC SQL COMMIT WORK;
            : DML 명령인 INSERT, DELETE ,UPDATE 문장을 수행한 경우에 유용하다.
            : DDL 명령은 자동 COMMIT 되므로 사용안해도 됨.
       
        -. EXEC SQL ROLLBACK WORK;            

출처 : Tong - ggypsy님의 배우자! 이것통

출처: https://blocked.tistory.com/396 [...낭만코딩 ^^]

반응형

'DBMS, 데이터베이스' 카테고리의 다른 글

레디스, Redis 이야기  (0) 2022.05.14
Pro*C 가이드 (pdf)  (0) 2022.05.10
Pro*C, gcc/cc로 *.pc 파일 컴파일  (0) 2022.05.10
Pro*C, 오라클 DBMS 연동  (0) 2022.05.10
Docker 설치하고 MariaDB 실행하기  (0) 2022.04.24

+ Recent posts