C언어03_Pro*C의 이해

4 minute read

이 글은 
https://kikook.tistory.com/499
글을 공부하며 정리한 글 입니다.

1. Pro*C란

  • SQL문을 포함한 C프로그램에서 DB에 접근 및 조작할 수 있는 프로그램으로 변환하기 위한 언어.
  • 프리 컴파일러이다.
  • 입력파일 내에 있는 EXEC SQL문을 이용하여 출력파일을 작성하고, 이 파일을 컴파일하고 링크해서 실행모듈 작성한다.
    1. C 프로그램을 작성한다.
    2. 프로그램을 컴파일하여 오브젝트 파일을 작성한다.
    3. 오브젝트 파일을 링크해서 실행 가능한 파일을 작성한다.
    4. 프로그램을 실행한다.
  • C프로그램 어디에든 배치해도 좋다.

  • EXEC SQL
    • SQL문을 호스트언어에 포함
    • 발생할 수 있는 언어상의 장애 최소화.
    • 모든 SQL문에는 EXEC SQL의 접두사를 붙인다.
    • 실행문 선언문에 관계없이 붙는 접두사이다.
  • EXEC ORACLE
    • SQL과는 호환성이 없다.
    • ORACLE 프리컴파일러 특유의 것이다.




실행문

  • DB에 대한 콜을 생성하는 SQL문
  • DML, DDL, DCL등이 있다.
  • 실행 후 SQLCA에는 일련의 리턴코드가 저장된다.
  • CONNECT, COMMIT, ROLLBACK 문의 다음에 첫 번째로 나타나는 SQL실행문 부터 논리적인 작업 단위가 새롭게 시작됨




선언문

  • 코드생성 X
  • 논리적 작업단위에 영향 없음.




2. Pro*C의 구성

어플리케이션 프롤로그

  • 변수를 정의하고 Pro*C 프로그램을 위한 일반적 준비 수행
  • 선언절, INCLUDE SQLCA문, CONNECT문

01) 선언절

  • C프로그램 내에서 사용된 모든 호스트 변수 선언.
  • 호스트 변수?
    • 호스트 변수의 데이터 타입은 선언절에서 호스트 언어를 사용하여 선언한다.
    • 데이터 타입은 테이블 정의시 사용되는 컬럼데이터 타입과 일치할 필요는 없다.
    • 선언절에서 명시적으로 선언
    • 영어 대/소문자 포맷 사용
    • SQL문 앞에서는 (:)콜론 붙이기
    • C문에서는 앞에 콜론을 붙이지 않음
    • SQL 예약어를 사용하지않는다.
    • 상수를 사용할 수 있는 곳에서만 사용한다.
    • 표지 변수가 붙어 있어도 상관 없다.

EXEC SQL BEGIN DECLARE SECTION; -- 시작
int pempno; /* 사번 */
char pname[11]; /* 성명 */
int pdeptno; /* 부서 */
EXEC SQL END DECLARE SECTION; -- 종료

EXEC SQL SELECT deptno, ename
INTO :pdeptno, :pname
FROM emp
WHERE empno = :pempno;

  • 표지변수?
    • 선언절에서 선언된 호스트변수에 1:1로 대응되는 임의 선택 변수
    • NULL 값을 취급하는데 유효하다.
    • 영어 대/소문자의 포맷 사용
    • 2byte 정수로 선언
    • SQL문 앞에서는 (:)콜론 붙이기
    • C문에서는 앞에 콜론을 붙이지 않음
    • SQL예약어를 사용하지 않는다.
    • SQL문 내에서는 대응하는 입력 호스트 변수를 앞에 붙여 사용
  • 호스트 변수로서의 포인터 선언
    • 포인터 변수는 C에서 통상적으로 행하는 방법으로 선언하여 선언절 내에서 사용할 수 있다.

EXEC SQL BEGIN DECLARE SECTION; -- 시작
int i, j * intptr;
char * cp;
EXEC SQL END DECLARE SECTION; -- 종료

EXEC SQL SELECT intfield
INTO :intptr
FROM DUAL;

  • VARCHAR의사타입의 선언
    • Pro*C에서는 VARCHAR타입을 사용할 수 있다.
    • 가변길이의 문자열을 처리할 수 있다.
    • 선언절에서 참조할 뿐이며, 확장된 c타입 또는 사전에 선언된 구조이다.

EXEC SQL BEGIN DECLARE SECTION;
VARCHAR jobDesc[40];
EXEC SQL END DECLARE SECTION;

//아래의 구조체로 확장할 수 있다.
struct{
  unsigned short int len;
  unsigned char arr[40];
}jobDesc



02) SQL통신영역의 선언

  • SQL 통신영역(SQLCA)에 대한 참조를 포함시켜 각 Pro*C 프로그램에서 발생하는 상황처리를 가능하게 함.

EXEC SQL INCLUDE SQLCA;

  • 프리 컴파일시 SQLCA파일의 위치를 알아야 한다.
    • “INCLUDE = “ 커맨드 라인 옵션 사용
    • Pro*C가 파일을 SYS$ORACLE:SQLCA 처럼 공동의 OS영역에서 발견할 수 있도록 파일의 정식 명칭을 지정한다.
    • PCC를 호출할 디렉토리 또는 디스크에 SQLCA를 카피한다.
  • SQLCA가 포함하고 있는 정보
    • 경고 플래그와 처리상황에 관한 정보
    • 에러코드
    • 진단정보



03) ORACA(SQLCA에 대한 확장)

  • EXEC SQL INCLUDE를 사용하여 ORACA의 정의 참조
  • 커냉드라인 옵션 또는 EXEC ORACLE OPTION에서 ORACA = YES 옵션 선택
  • 정보
    • orastxt : SQL문의 텍스트 ( oracle이 해석한 sql문의 내용 조사 가능. COMMIT, FETCH, CONNECT제외 )
    • orasfnm : 에러가 있는 파일 이름
    • orastxtf : SQL문 보존 플래그 ( 어느조건으로 보존할 지 선택 )
      1. 디폴트값은 SQL문을 보존하지 않음
      2. SQLERROR가 있는 SQL만을 보존한다.
      3. SQLERROR및 SQLWARN이 있는 SQL보존
      4. SQL문 전부 보존
    • DEBUG처리 사용 허가 플래그
      • 0또는 1을 설정할 수 있으며, 1을 설정한 경우 모든 DEBUG처리를 사용할 수 있다.
    • orahchf : 커서 캐쉬검사

04) ORACLE 접속


EXEC SQL CONNECT :oracleid IDENTIFIED BY :oraclepwd;

  • CONNECT문은 프로그램 내에서 최초의 SQL문
  • 선언문과 C코드만을 CONNECT문 앞에 놓을 수 있다.
  • 비밀번호를 따로 지정할 경우 유저명과 패스워드 양쪽에 대해 호스트 변수를 사용해야 한다.(고정 또는 가변길이 문자열중 하나로 선언)
  • CONNECT문을 수행하기 전, 양쪽 호스트 변수를 초기화 시켜야 한다.
  • CONNECT는 프로그램의 최초 실행문이지만, 논리적 작업단위의 시작이다.



어플리케이션 본체

  • 데이터를 조작하기 위한 INSERT, UPDATE 등의 SQL문을 포함
  • 데이터 정의문이 포함되며, 테이블, 뷰, 인덱스 등의 데이터 구조를 작성하거나 정의하기 위해 사용됨
  • 처리 시 필요로 하는 코드의 전후에 어떠한 C코드를 지정해도 상관없다.
  • DECLARE STATEMENT 문
  • DECLARE DATABASE 문
  • EXEC ORACLE 옵션

01) 행 삽입


EXEC SQL BEGIN DECLARE SECTION;
  VARCHAR uid[20]
  VARCHAR pwd[20];
  int empno;
  VARCHAR ename[15];
  VARCHAR job[10];
  float sal;
  int deptno;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

void main(void)
{
  int sret; // scanf로 리턴받는 코드
  // Oracle 로그
  strcpy(uid.arr, "SCOTT");
  uid.len = strlen(uid.arr);
  strcpy(pwd.arr , "TIGER");
  pwd.len = strlen(pwd.arr);
  
  EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
  
  printf("Connected to ORACLE user : %s\n\n\n", uid.arr);
  while(1)
  {
    printf("Enter employee number(or 0 to end) : ");
    sret = scanf("%d", &empno);
    if(sret == EOF || sret == 0 || empno == 0 )
      break;
    
    printf("Enter employee name : ");
    scanf("%s", ename.arr);
    ename.len = strlen(ename.arr);
    
    printf("Enter employee's job : ");
    scanf("%s", job.arr);
    job.len = strlen(job.arr);
    
    printf("Enter employee salary : ");
    scanf("%f", &sal);
    
    printf("Enter employee deptno : ");
    scanf("%d", &deptno);
    
    EXEC SQL INSERT INTO EMP
      ( empno
        , ename
        , job
        , sal
        , deptno )
    VALUES
      ( :empno
      , :ename
      , :job
      , :sal
      , :deptno );
    
    EXEC SQL COMMIT WORK;
    printf("Employee %s added. \n\n", ename.arr);
  }
  
  EXEC SQL COMMIT WORK RELEASE;
  exit(0);
}