ORACLE의 기능에 의하여, 유저의 작업 모두가 실행하면 바로 COMMIT되는 것이 아니다. 다시말해서 ORACLE에서는 COMMIT 을 행하기 전에 모든 트랜잭션이 완료되어 있는지를 유저 자신이 확인하도록 되어 있다.
ORACLE은 BEFORE 이미지 파일을 사용하여, 데이터베이스의 일관성을 보호하고 있다. BEFORE 이미지 파일에는 트랜잭션이 시작하기 전의 상태로 데이터베이스의 블록이 보존된다. 상황에 따라 이들의 블록이 데이터베이스 파일에 다시 기록되어, 트랜잭션에 의해 변경된 부분이 변경 전의 상태로 되돌려 진다. 이 같은 처리는 다음과 같은 경우 발생한다.
유저에 의한 ROLLBACK WORK
유저 프로세스 내의 ORACLE로부터의 이상 종료
프로세스간의 데드록
시스템 장애(H/W OR S/W)
4.1 COMMIT WORK
COMMIT WORK 문은 현재 진행 중인 논리적인 작업단위를 종료하게 하고, 이 작업단위 내에서 행해진 변경을 모두 확정한다.
EXEC SQL COMMIT WORK [RELEASE];
RELEASE 옵션 파라미터는 프로그램이 소유하고 있는 자원을 모두 리턴하고, 데이터베이스에서 로그로프한다.
4.2 ROLLBACK WORK
ROLLBACK WORK 문은 현재 진행 중인 논리적인 작업단위를 종료하게 하고, 이 작업단위에서 행한 변경을 취소한다.
EXEC SQL ROLLBACK WORK [RELEASE];
유저는 RELEASE 옵션을 사용해서 최후의 작업단위를 반드시 명시적으로 COMMIT 또는 ROLLBACK해야 한다.
5.1 표지 변수에 리턴된 값의 사용
어느 호스트 변수에도 임의 선택 변수인 표지 변수를 대응시킬 수 있다. 이 표지 변수를 사용하면 각각의 필드 값이 어떤 경우인지 알 수 있다.
값 의미
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
0 리턴되는 값은 호스트 변수에 보존된다. 이것은 널도 아니고,
절사도 되지 않는다.
-1 리턴된 값은 널이다. 호스트 변수의 값은 정의되지 않는다.
20 리턴된 값은 절사되어 있다. 호스트 변수의 폭이 충분하지 않다.
표지 변수에 설정된 값은 절사되기 전의 폭이다
5.2 SQLCA의 구조
SQLCA 는 프로그램의 실행에 관한 정보를 교환하기 위해, 모든 Pro*C 프로그램에서 사용한다. SQLCA는 각각의 트랜잭션에 대해서 널 값의 무시여부, 쿼리를 시작하고 나서 데이터의 변경 여부등을 표시하므로, 프로그래머는 각각의 데이터 상태를 확인할 수 있다.
5.2.1 SQLCA를 참조하는 타이밍
SQLCA는 각 SQL 실행문의 실행 때마다 갱신된다. 따라서 프로그래머는 각 실행문 뒤에서 SQLCA를 검색해야 한다. 특히 각 DML 문 뒤에서는 SQLCA를 검색할 필요가 있다. 이는 테이블 속의 일부의 행만을 처리한 뒤에 INSERT 및 UPDATE 문이 실패한다면, 유저는 데이터베이스을 어떤 일관성 있는 상태로 회복하기 위해 ROLLBACK WORK 커맨드를 실행해야 하기 때문이다.
WHENEVER 문을 사용하면 이상 상태를 검출하고 그 상태에 따라 적절히 동작을 지정할 수 있다. 다음은 WHENEVER 문의 디폴트 값이다.
EXEC SQL WHENEVER anyerror CONTINUE;
5.2.2 SQLCA의 각 요소의 의미
struct sqlca {
char sqlcaid[8];
long sqlcabc;
long sqlcode;
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 4바이트 2진 정수이고, SQL 문의 실행결과를 나타낸다.
0 실행이 정상 종료
1403 NOT FOUND
음수 프로그램 또는 시스템 장애
*sqlca.sqlerrm.sqlerrml sqlca.sqlerrm.sqlerrmc의 텍스트의 길이
*sqlca.sqlerrm.sqlerrmc 가변 길이의 문자열이고, sqlca.sqlcode 내에
표시된 에러번호에 대응하는 에러메세지
*sqlca.sqlerrd 4바이트 2진 정수 배열 ORACLE RDBMS의 내부상황을
파악하기 위해 사용. sqlca.sqlerrd[2]는 INSERT나 UPDATE
처럼 DML 처리에 대해서 몇 개의 행이 처리 됐는지를 나타냄
*sqlca.sqlwarn 프리컴파일 중에 발생한 여러가지 상황에 대한 경고
sqlca.sqlwarn[0] "W"가 설정된 경우 1개 이상의 경고가 설정되어 있음
5.3 WHENEVER 문
에러를 검출할 때 어떤 처리를 취해야 할 지를 결정한다.
EXEC SQL WHENEVER [SQLERROR | SQLWARNING | NOT FOUND]
[STOP | CONTINUE | GOTO stmt-label];
SQLERROR sqlca.sqlcode가 -1인 경우에 설정
SQLWARNING sqlca.sqlwarn[0]에 "W"가 설정되어 있는 경우에 설정
NOT FOUND sqlca.sqlcode가 1403인 경우에 설정
STOP 프로그램을 종료시키고 논리적인 작업단위는 ROLLBACK 된다.
CONTINUE sqlca의 상태를 무시하고 프로그램을 계속 진행한다.
GOTO 지정한 라벨이 붙은 문으로 제어를 옮긴다.
6. 동적 정의문
6.1 동적 정의문의 정의
동적 정의문이란, 컴파일시에 정의되지 않는 SQL 문이다. 다시 말해서, 동적 정의문은 각각의 실행 때마다 변경이 가능하고, 실제로 많은 경우에 변경된다.
6.2 동적 정의문의 종류
방법 1 : EXECUTE IMMEDIATE 문의 사용
모든 SQL 문(SELECT 문 제외)을 프리컴파일해서 이것을 실행한다.
SQL 문은 상수 또는 호스트 변수 중 어느 것이라도 상관없다.
SQL 문에는 호스트 변수를 포함하지 않는다.
방법 2 : PREPARE 문 및 EXECUTE 문의 사용
모든 SQL 문(SELECT 문 제외)을 받아들여 이것을 수행한다.
SQL 문 중에 호스트 변수를 포함할 수 있다.
방법 3 : PREPARE 문 및 FETCH 문의 사용
선택을 행할 수 있다. SQL 문 중에 호스트 변수를 포함할 수 있다.
이 방법은 PREPARE, DECLARE, OPEN, FETCH의 순서로 행한다.
방법 4 : 바인드 및 정의 기술자의 사용
1행의 SELECT 및 여러 행의 SELECT를 포함하는 모든 SQL 문을
사용할 수 있다.
6.3 EXECUTE IMMEDIATE 의 사용
/* 예제 #10 */
#include
/***************************************************************
This is is a sample Pro*C program which will prompt for a
WHERE clause to be used in an update statement. This is to be
used with EXECUTE IMMEDIATE.
***************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20];
VARCHAR pwd[20];
char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
void main(void)
{
char where[80];
int scode;
/* log into ORACLE */
strcpy(uid.arr, "SCOTT"); /* copy the user name */
uid.len = strlen(uid.arr);
strcpy(pwd.arr, "TIGER"); /* copy the password */
pwd.len = strlen(pwd.arr);
EXEC SQL WHENEVER SQLERROR STOP;
EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
printf("Connected to ORACLE user : %s\n", uid.arr);
strcpy(select, "UPDATE EMP SET COMM = 100 WHERE");
printf("Please enter where clause for the following : \n");
printf("%s", select);
scode = scanf("%s", where);
if(scode == EOF !! scode == 0)
{
printf("Invalid entry. \n");
exit(1);
}
strcat(select, where);
EXEC SQL EXECUTE IMMEDIATE :select;
printf("%d records updated. \n", sqlca.sqlerrd[2]);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
6.4 PREPARE 및 EXECUTE 의 사용
/* 예제 #11 */
#include
/***************************************************************
This is is a sample Pro*C program which will prompt for a
WHERE clause to be used in an update statement. This is to be
used with PREPARE and EXECUTE.
***************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20];
VARCHAR pwd[20];
float comm;
char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
void main(void)
{
char where[80];
int scode;
/* log into ORACLE */
strcpy(uid.arr, "SCOTT"); /* copy the user name */
uid.len = strlen(uid.arr);
strcpy(pwd.arr, "TIGER"); /* copy the password */
pwd.len = strlen(pwd.arr);
EXEC SQL WHENEVER SQLERROR GOTO errrpt;
EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
printf("Connected to ORACLE user : %s\n", uid.arr);
strcpy(select, "UPDATE EMP SET COMM = :comm WHERE");
printf("Please enter where clause for the follwing : \n");
printf("%s", select);
scode = scanf("%s", where);
if(scode == EOF !! scode == 0)
{
printf("Invalid entry. \n");
exit(1);
}
strcat(select, where);
EXEC SQL PREPARE S1 FROM :select;
printf("Please enter commission : ");
scanf("%f", &comm);
EXEC SQL EXECUTE S1 USING :comm;
printf("%d records updated. \n", sqlca.sqlerrd[2]);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
exit(0);
errrpt:
printf("\n %70s \n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
6.5 PREPARE, DECLARE, OPEN, FETCH, CLOSE 의 사용
/* 예제 #12 */
#include
/***************************************************************
This is is a sample Pro*C program which will prompt for a
WHERE clause to be used in a select statement.
This sample uses PREPARE, DECLARE, OPEN, FETCH, CLOSE
since this may be a multi-row select and world require a cursor.
***************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20];
VARCHAR pwd[20];
int deptno;
float sal;
char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
void main(void)
{
char where[80];
int i, scode;
/* log into ORACLE */
strcpy(uid.arr, "SCOTT"); /* copy the user name */
uid.len = strlen(uid.arr);
strcpy(pwd.arr, "TIGER"); /* copy the password */
pwd.len = strlen(pwd.arr);
EXEC SQL WHENEVER SQLERROR GOTO errrpt;
EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
printf("Connected to ORACLE user : %s\n", uid.arr);
strcpy(select, "SELECT ENAME, SAL FROM EMP ");
printf("Please enter where clause for the following : \n");
printf("%s", select);
scode = scanf("%s", where);
if(scode == EOF !! scode == 0)
{
printf("Invalid entry. \n");
exit(1);
}
strcat(select, where);
EXEC SQL PREPARE S1 FROM :select;
EXEC SQL DECLARE C1 CURSOR FOR S1;
EXEC SQL OPEN C1;
printf("Employee \tSalary \n");
printf("--------------\t-----------\n");
EXEC SQL WHENEVER NOT FOUND GOTO endloop;
for(i = 0; ; i++)
{
EXEC SQL FETCH C1 INTO :ename, :sal;
printf("%10s\t%6.2f\n", ename, sal);
}
endloop:
printf("\n\n%d records selected.\n", i);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
exit(0);
errrpt:
printf("\n %70s \n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
7.1 STORED PROCEDURE 의 사용
/* calldemo.sql */
rem
Rem calldemo.sql -
Rem DESCRIPTION
Rem
Rem RETURNS
Rem
CREATE OR REPLACE PACKAGE calldemo AS
TYPE name_array IS TABLE OF emp.ename%type
INDEX BY BINARY_INTEGER;
TYPE job_array IS TABLE OF emp.job%type
INDEX BY BINARY_INTEGER;
TYPE sal_array IS TABLE OF emp.sal%type
INDEX BY BINARY_INTEGER;
PROCEDURE get_employees(
dept_number IN number, -- department to query
batch_size IN INTEGER, -- rows at a time
found IN OUT INTEGER, -- rows actually returned
done_fetch OUT INTEGER, -- all done flag
emp_name OUT name_array,
job OUT job_array,
sal OUT sal_array);
END calldemo;
/
CREATE OR REPLACE PACKAGE BODY calldemo AS
CURSOR get_emp (dept_number IN number) IS
SELECT ename, job, sal FROM emp
WHERE deptno = dept_number;
PROCEDURE get_employees(
dept_number IN number,
batch_size IN INTEGER,
found IN OUT INTEGER,
done_fetch OUT INTEGER,
emp_name OUT name_array,
job OUT job_array,
sal OUT sal_array) IS
BEGIN
IF NOT get_emp%ISOPEN THEN -- open the cursor if
OPEN get_emp(dept_number); -- not already open
END IF;
done_fetch := 0; -- set the done flag FALSE
found := 0;
FOR i IN 1..batch_size LOOP
FETCH get_emp INTO emp_name(i), job(i), sal(i);
IF get_emp%NOTFOUND THEN -- if no row was found
CLOSE get_emp;
done_fetch := 1; -- indicate all done
EXIT;
ELSE
found := found + 1; -- count row
END IF;
END LOOP;
END;
END;
/
/* 예제 #13 */
#include
#include
/***************************************************************
This program connects to ORACLE using the SCOTT/TIGER account.
The program declares several host arrays, then calls a PL/SQL
stored procedure (GET_EMPLOYEES in the CALLDEMO package)
that fills the table OUT parameters. The PL/SQL procedure returns
up to ASIZE values.
****************************************************************/
EXEC SQL INCLUDE sqlca.h;
typedef char asciz[20];
typedef char vc2_arr[11];
EXEC SQL BEGIN DECLARE SECTION;
/* User-defined type for null-terminated strings */
EXEC SQL TYPE asciz IS STRING(20) REFERENCE;
/* User-defined type for a VARCHAR array element. */
EXEC SQL TYPE vc2_arr IS VARCHAR2(11) REFERENCE;
asciz username;
asciz password;
int dept_no; /* which department to query? */
vc2_arr emp_name[10]; /* array of returned names */
vc2_arr job[10];
float salary[10];
int done_flag;
int array_size;
int num_ret; /* number of rows returned */
EXEC SQL END DECLARE SECTION;
long SQLCODE;
void print_rows(); /* produces program output */
void sql_error(); /* handles unrecoverable errors */
main()
{
int i;
char temp_buf[32];
/* Connect to ORACLE. */
EXEC SQL WHENEVER SQLERROR DO sql_error();
strcpy(username, "scott");
strcpy(password, "tiger");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnected to ORACLE as user: %s\n\n", username);
printf("Enter department number: ");
gets(temp_buf);
dept_no = atoi(temp_buf);
/* Print column headers. */
printf("\n\n");
printf("%-10.10s%-10.10s%s\n", "Employee", "Job", "Salary");
printf("%-10.10s%-10.10s%s\n", "--------", "---", "------");
/* Set the array size. */
array_size = 10;
done_flag = 0;
num_ret = 0;
/* Array fetch loop.
* The loop continues until the OUT parameter done_flag is set.
* Pass in the department number, and the array size--
* get names, jobs, and salaries back. */
for ( ; ; )
{
EXEC SQL EXECUTE
BEGIN calldemo.get_employees
(:dept_no, :array_size, :num_ret, :done_flag,
:emp_name, :job, :salary);
END;
END-EXEC;
print_rows(num_ret);
if(done_flag) break;
}
/* Disconnect from the database. */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void print_rows(int n)
{
int i;
if (n == 0)
{
printf("No rows retrieved.\n");
return;
}
for (i = 0; i < n; i++)
printf("%10.10s%10.10s%6.2f\n", emp_name[i ], job[i ], salary[i ]);
}
/* Handle errors. Exit on any error. */
void sql_error()
{
char msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
buf_len = sizeof(msg);
sqlglm(msg, &buf_len, &msg_len);
printf("\nORACLE error detected:");
printf("\n%.*s \n", msg_len, msg);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
8. Pro*C/C++의 사용
8.1 디렉토리 또는 경로의 설정
OS에서 디렉토리 또는 경로를 사용하고 있는 경우 경로 또는 디렉토리의 이름이 장치의 지정과 함께 올바른 지를 확인해야 한다.
8.2 커맨드 구문
일반적인 커맨드 구문은 다음과 같다.
PCC INAME = filename {option=value (option=value …)}
8.2.1 필수 인수
필수 인수는 "INAME = 파일명" 하나뿐이다. 파일의 확장자나 파일타입을 지정하지 않는 경우 "HOST = 언어"를 인수로서 지정해야 한다.
Pro*C에서 입력파일 및 출력파일에 대한 파일타입 및 확장자의 디폴트값은 다음과 같다.
OS 입력파일타입 또는 확장자 출력파일타입 또는 확장자
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VAX/VMS .pc .c
IBM/VM/CMS csql c
UNIX .pc .c
8.2.2. Pro*C의 실행시 옵션
실행시에는 복수의 옵션을 사용할 수 있다.
OPTION = value
· AREASIZE
· ASACC
· ERRORS
· HOLD_CURSOR/RELEASE_CURSOR
· HOST
· INCLUDE
· IRECLEN
· LNAME
· LRECLEN
· LTYPE
· MAXLITERAL
· MAXOPENCURSOR
· ONAME
· ORACA
· ORECLEN
· PAGELEN
· REBIND
· SELECT_ERROR
· USERID
· XREF
|