
오류 처리하기
Pro*C에서 실행시 오류가 발생하였을 때에 오류처리하는 방법은 여러가지가 있습니다.
1. SQLCA(SQL Communication Area)를 이용하는 방법
- 오류가 발생하면 struct sqlca sqlca; 전역 구조체 변수에 오류상태를 저장해줍니다
- 오류 여부는 저장된 상태값(오류코드)으로 판단합니다.
2. EXEC SQL WHENEVER <condition> <action>; 을 이용하는 방법
    - 직관적이지 않고 잘못사용하면 무한 loop에 빠질 수 있습니다.
- 오류내용은 SQLCA방식으로 확인해야 합니다.
3. ORACA(ORACLE Communication Area)를 이용하는 방법
- 추가적인 시스템 오버헤더가 있으며 거의 모니터링 수준으로 개발자들이 사용하기에는 적합하지 않습니다.
- SQLCA를 기본으로 하고 모니터링할 것이 있을 때에 사용합니다.
SQLCA를 이용하는 방법에 대해서만 알아보겠습니다.
SQLCA (SQL Communication Area)를 이용한 오류처리
SQLCA 방법은 Pro*C에서 SQL문을 수행하는 단계마다 오류가 발생하면 struct sqlca sqlca;라는 전역변수에 오류 상태를 저장하여 줍니다. (C언어의 errno 전역변수와 비슷한 형태 제공)
SQLCA방식을 사용하려면 sqlca.h 파일을 include해야 합니다.
#include <sqlca.h>
또는
EXEC SQL INCLUDE SQLCA;
struct sqlca 구조체의 구조는 아래와 같습니다.
struct sqlca
{
     char sqlcaid[8];       /* "SQLCA" 문자열이 저장됨 */
     long sqlabc;           /* sizeof(struct sqlca) 값*/
     long sqlcode;          /* 오류가 발생시 oracle error code  저장 */
     
     struct
     {
         unsigned short sqlerrml;  /* 오류메시지 길이 */
         char sqlerrmc[70];        /* 오류메시지 */
     } sqlerrm;
     char sqlerrp[8];    /* 예약됨 */
     long sqlerrd[6];    
     char sqlwarn[8];
     char sqlext[8];     /* 예약됨 */
};
struct sqlca sqlca;      /* 전역변수 */
sqlca.sqlcode
sqlca.sqlcode에는 오류코드가 저장됩니다. ORA-00001과 같은 오라클의 오류코드 중 ORA를 뺀값을 가집니다.
sqlca.sqlcode == 0
    - 정상적으로 처리됨
sqlca.sqlcode > 0 
    - 조회 또는 INSERT 건수가 없다는 의미입니다.
sqlca.sqlcode == 1403 
    - 조회된 데이터가 없다는 의미.
sqlca.sqlcode == 100 
    - INSERT된 데이터가 없다는 의미.(단 컴파일 옵션이 MODE=ANSI 일때)
     이 경우는 INSERT - SELECT문에서만 발생함.
sqlca.sqlerrm 구조체
sqlca.sqlerrm.sqlerrml
    - 오류메시지의 길이(sqlca.sqlerrm.sqlerrmc에 저장된 문자열의 길이)
sqlca.sqlerrm.sqlerrmc
    - 오류메시지 내용.
    - 오류메시지는 Null terminate 문자열이 아니므로 반드시 sqlca.sqlerrm.sqlerrml로 크기를 체크해야 함.
    - 오류가 잘리지 않고 전체를 보여주려면 sqlglm( )함수를 이용함 
sqlca.sqlerrd
sqlca.sqlerrd[0]
    - 다른 용도로 예약됨 
sqlca.sqlerrd[1]
    - 다른 용도로 예약됨
sqlca.sqlerrd[2]
    - 처리 건수가 저장됨
    - SELECT: 조회 건수
    - FETCH : 누적 조회 건수
    - INSERT: INSERT 건수
    - UPDATE: UPDATE 건수
    - DELETE: DELETE 건수 
sqlca.sqlerrd[3]
    - 다른 용도로 예약됨
sqlca.sqlerrd[4]
    - SQL문 파싱시 오류가 발생한 위치 (첫 바이트는 0부터 시작함)
sqlca.sqlerrd[5]
    - 다른 용도로 예약됨 
sqlca.sqlwarn
slqca.sqlwarn[0] 
    - 경고 flag W값 설정됨
slqca.sqlwarn[1] 
    - output data가 truncate됨. indicator 변수를 사용할 경우에 -1 또는 0이 아닌 경우
slqca.sqlwarn[2] 
    - 사용안함
slqca.sqlwarn[3] 
    - SELECT 문의 column  갯수와 INTO문의 변수 갯수가 다른 경우
slqca.sqlwarn[4] 
    - DELETE, UPDATE문에 WHERE절이 없는 경우
slqca.sqlwarn[5] 
    - 사용안함
slqca.sqlwarn[6] 
    - 다른 용도로 예약됨
slqca.sqlwarn[7] 
    - 다른 용도로 예약됨 
오류처리 예제
    char emp_name[54];
    long dept_number;
    long salary;
    long emp_number;
    ......
    EXEC SQL  AT :db_con1  DECLARE emp_cursor CURSOR FOR
    SELECT ename, empno, sal
    FROM emp
    WHERE deptno = :dept_number;
    EXEC SQL OPEN emp_cursor;
    if(sqlca.sqlcode != 0) {
        fprintf(stderr, "CURSOR OPEN ERROR: %.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    while(1) {
        EXEC SQL FETCH emp_cursor
        INTO :emp_name, :emp_number, :salary;
        if(sqlca.sqlcode != 0) {  // 오류이면
            if(sqlca.sqlcode == 1403) {  // 더 이상 조회된 내용이 없는 경우
                printf("조회된 데이터가 더 없습니다.\n");
                break;
            } else {
                fprintf(stderr, "%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
                return -1;
            }
        }
        
        printf("성명: %s \t사번: %ld \t급여: %f\n", emp_name, emp_number, salary);
    }
    
    ......
sqlglm( )
- 오류 메시지가 잘리지 않고 상세 오류 메시지를 얻는 함수
#include <sqlcpr.h>
void sqlglm(char *message_buffer, size_t *buffer_size, size_t *message_length);
Pro*C에서 SQL문을 수행 도중 발생한 오류를 sqlca.sqlerrm로 처리 시에 메시지가 잘리는 것 보완하기 위하여 만들어진 함수입니다. (sqlca.sqlerrm의 길이는 최대 70바이트) 오류 메시지는 최대 512바이트이며 이보다 작게 잡을 경우에 잘려질 수 있습니다.
파라미터
message_buffer
    - 오류 메시지를 저장할 buffer
buffer_size
    - 오류 메시지를 저장하기 위해 할당된 buffer 크기 
message_length
    - 실제 오류 메시지 길이
RETURN
없음
sqlglm() 사용 예제.
   char     err_msg[512];
   size_t   buf_size = 512;
   size_t   msg_len;
    ......
    EXEC SQL  AT :db_con1  INSERT INTO emp (empno, ename, sal, deptno)
    VALUES (:emp_number, :emp_name, :salary, :dept_number);
    // SQL 수행오류이면
    if(sqlca.sqlcode != 0) { 
        sqlglm(err_msg, &buf_size, &msg_len);
        fprintf(stderr, "%.*s\n", msg_len, err_msg);
        return -1;
    }
See Also : Pro*C 목차 및 Sample Source
'Oracle > Pro*C' 카테고리의 다른 글
| Pro*C 6. 대량처리 (배열처리) (0) | 2019.09.25 | 
|---|---|
| Pro*C 5-2. 오류 처리하기 (WHENEVER) (0) | 2019.09.25 | 
| Pro*C 4. 기본 SQL문 실행 (0) | 2019.09.25 | 
| Pro*C 3. 변수선언과 INCLUDE (0) | 2019.09.25 | 
| Pro*C 2. DB 접속 해제 및 Commit / Rollback (0) | 2019.09.25 |