PL/SQL은 SQL에 프로그래밍 구조 (조건문, 반복문)을 더한 절차적 언어
또한, ProC는 언어가 아닌 C언어 코드에 SQL문장을 삽입해 오라클 DB랑 연동할 수 있는 전처리기
SQL을 C코드처럼 쓸 수 있는 Embedded SQL 방식
.pc (프로세스 컴포넌트 아님) 확장자를 가진 파일을 Pro*C 컴파일러가 C코드로 변환하고 -> 다시 일반 C 컴파일러로 컴파일해 실행
주로 고성능 시스템이나 레거시 금융 시스템에서 많이 쓰임
본예제는 Stored Procedure와 Package를 사용하지 않고 Pro*C 안에서 직접 PL/SQL 프로그래밍을 하는 과정으로 진행하겠음
inlcude 절 선언 - 단일 행 추출 프로그램과 동일하게 선언
#include <stdio.h>
#include <sqlca.h>
호스트 변수 선언
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[80]; /* 디비 유저 */
VARCHAR pwd[20];/* 디비 비밀번호 */
int empno; /* 사원번호 */
VARCHAR ename[20]; /* 사원이름 */
EXEC SQL END DECLARE SECTION;
메인 함수 작성 - 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);
}
}
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 출력
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;
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);
}
EXEC SQL
SELECT empno, ename
INTO :empno, :ename // 호스트 변수
FROM emp
WHERE empno = 7369;
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이 없거나 틀리면 잘못된 문자열이 전달됨 😢
strcpy((char *)var.arr, "값");
var.len = strlen((char *)var.arr);
변수를 선언하였다 하더라도 쓰레기값이 남아있을 수 있으므로 메모리세팅함수인 memset을 통해 깔끔한 값으로 초기화 하는 것
memset(c_commands, 0x00, sizeof(c_commands));
📌 이건 Oracle DB 접속 또는 배치 작업 전에
명령어를 저장할 배열(c_commands)을 초기화하는 코드입
이유:
C에서는 배열이 생성되었을 때 쓰레기값이 남아 있을 수 있음 -> 이걸 깔끔히 0으로 초기화해서 오류를 방지