[Pro*C] PL/SQL 호출 프로그램

세나정·2025년 4월 24일
0

Pro*C

목록 보기
1/1
post-thumbnail

PL/SQL 호출 프로그램

PL/SQL (Procedural Languege/SQL)?

PL/SQL은 SQL에 프로그래밍 구조 (조건문, 반복문)을 더한 절차적 언어
또한, ProC는 언어가 아닌 C언어 코드에 SQL문장을 삽입해 오라클 DB랑 연동할 수 있는 전처리기

  • SQL을 C코드처럼 쓸 수 있는 Embedded SQL 방식

  • .pc (프로세스 컴포넌트 아님) 확장자를 가진 파일을 Pro*C 컴파일러가 C코드로 변환하고 -> 다시 일반 C 컴파일러로 컴파일해 실행

  • 주로 고성능 시스템이나 레거시 금융 시스템에서 많이 쓰임


예제

사원번호 7369의 사원 데이터를 추출하여 사원 번호와 사원 명을 출력함

본예제는 Stored Procedure와 Package를 사용하지 않고 Pro*C 안에서 직접 PL/SQL 프로그래밍을 하는 과정으로 진행하겠음

1단계

inlcude 절 선언 - 단일 행 추출 프로그램과 동일하게 선언

#include <stdio.h>
#include <sqlca.h>

2단계

호스트 변수 선언

EXEC SQL BEGIN DECLARE SECTION;
	VARCHAR uid[80]; /* 디비 유저 */
    VARCHAR pwd[20];/* 디비 비밀번호 */
    
    int empno; /* 사원번호 */
    VARCHAR ename[20]; /* 사원이름 */ 
EXEC SQL END DECLARE SECTION;

3단계

메인 함수 작성 - DB 접속
단일 행 추출 프로그램과 동일하게 지역 데이터베이스 접속 방식으로 프로그램을 작성

void main()
{
/* login oracle 부분 */

strcpy((char *)uid.arr, "userid");
uid.len = (short) strlen((char *)uid.arr);

strcpy((char *)pwd.arr, "password");
pwd.len = (short) strlen((chat *)pwd.arr);

EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

if (sqlca.sqlcode != 0) {
	printf("유효하지 않은 아이디/비번 SQLCODE : [%d]\n", sqlca.sqlcode);
    exit(0);
	}
}

4단계

PL/SQL 호출

이제 아래에서 사원번호가 7369인 데이터를 추출하는 PL/SQL을 내부적으로 호출하여 PL/SQL안에서 데이터 추출에 필요한 변수를 선언한 후에 데이터를 추출하여 호스트 변수에 할당함

/* Retrieve the current employee number (사원번호 검색) */

/* PL/SQL문 기술 */
	EXEC SQL EXECUTE
    	DECLARE
          v_empno emp.empno%TYPE;
          v_ename emp.ename%TYPE;
      
        BEGIN  
          SELECT empno, ename
              INTO v_empno, v_ename
              FROM emp
              WHERE empno = 7369;

            :empno := v_empno;
            :ename := v_ename;
        END
    END-EXEC;
    
    printf("EMPNO : [%d] / ENAME : [%s]\n", empno, ename.arr);

총 완성본

#include <stdio.h>
#include <splca.h>

EXEC SQL BEGIN DECLARE SECTION;
	VARCHAR udi[80]; /* 디비 유저 */
    VARCHAR pwd[20];/* 디비 비밀번호 */
    
    int empno; /* 사원번호 */
    VARCHAR ename[20]; /* 사원이름 */ 
EXEC SQL END DECLARE SECTION;

void main()
{
/* login oracle 부분 */
strcpy((char *)uid.arr, "userid");
uid.len = (short) strlen((char *)uid.arr);

strcpy((char *)pwd.arr, "password")
pwd.len = (short) strlen((chat *)pwd.arr);

EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

if (sqlca.sqlcode != 0) {
	printf("유효하지 않은 아이디/비번 SQLCODE : [%d]");
    exit(0);
	}
}
/* Retrieve the current employee number (사원번호 검색) */

/* PL/SQL문 기술 */
	EXEC SQL EXECUTE
    	DECLARE
          v_empno emp.empno%TYPE;
          v_ename emp.ename%TYPE;
      
        BEGIN  
          SELECT empno, ename
              INTO v_empno, v_ename
              FROM emp
              WHERE empno = 7369;

            :empno := v_empno;
            :ename := v_ename;
        END
    END-EXEC;
    
    printf('EMPNO : [%d] / ENAME : [%s]', empno, ename.arr);
    exit(0);
 }

전체흐름

[1] EXEC SQL CONNECT → Oracle 연결
[2] EXEC SQL EXECUTE → PL/SQL로 사원 정보 조회
[3] :empno, :ename 에 결과 매핑
[4] printf 출력

정리

1. 헤더 선언부

EXEC SQL BEGIN DECLARE SECTION;
    VARCHAR uid[80];       // Oracle 로그인용 아이디
    VARCHAR pwd[20];       // Oracle 로그인용 비밀번호
    int empno;             // 사원번호
    VARCHAR ename[20];     // 사원이름 (VARCHAR: Oracle 문자열 타입)
EXEC SQL END DECLARE SECTION;
  • Oracle DB와 통신할 변수를 선언
  • DECLARE SECTION 안에 선언된 변수만 SQL 문에서 쓸 수 있음
  • VARCHAR는 Pro*C 전용 문자열 구조 (arr + len)

2. DB 접속 처리부

strcpy((char *)uid.arr, "userid");
uid.len = strlen((char *)uid.arr);

strcpy((char *)pwd.arr, "password");
pwd.len = strlen((char *)pwd.arr);

EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

if (sqlca.sqlcode != 0) {
    printf("유효하지 않은 아이디/비번 SQLCODE : [%d]\n", sqlca.sqlcode);
    exit(1);
}

3. 데이터 조회

EXEC SQL
    SELECT empno, ename
    INTO :empno, :ename // 호스트 변수
    FROM emp
    WHERE empno = 7369;

궁금한 점

왜 uid.len처럼 길이를 사용해야만 하는 걸까?

Pro*C의 VARCHAR 타입은 문자열 길이(.len)를 따로 저장해야 하기 때문

VARCHAR의 실제구조는 아래와 같음

typedef struct {
  unsigned short len; // 실제 문자열 길이
  char arr[n];        // 실제 문자열
} VARCHAR;

그렇기 때문에

VARCHAR uid[80]; 은 => uid.arr은 'userid'를 저장 / uid은 문자열의 길이 저장

Oracle SQL과 통신할 때 Pro*C는 이렇게 행동함:

uid.arr를 읽어서 문자열 값을 Oracle로 보냄

그때 uid.len의 값만큼만 사용해요! → len이 없거나 틀리면 잘못된 문자열이 전달됨 😢

꿀팁

VARCHAT를 쓸 땐 항상 세트처럼 기억하기

strcpy((char *)var.arr, "값");
var.len = strlen((char *)var.arr);

db접속시에 memset을 사용하는 이유

변수를 선언하였다 하더라도 쓰레기값이 남아있을 수 있으므로 메모리세팅함수인 memset을 통해 깔끔한 값으로 초기화 하는 것

memset(c_commands, 0x00, sizeof(c_commands));

📌 이건 Oracle DB 접속 또는 배치 작업 전에
명령어를 저장할 배열(c_commands)을 초기화하는 코드입

이유:
C에서는 배열이 생성되었을 때 쓰레기값이 남아 있을 수 있음 -> 이걸 깔끔히 0으로 초기화해서 오류를 방지
profile
기록, 꺼내 쓸 수 있는 즐거움

0개의 댓글