'Language'에 해당되는 글 463건

  1. 2016.08.04 [Java] ClassLoader API
  2. 2015.05.20 [번역] 런타임 에러 처리 (Handling Runtime Errors)
  3. 2015.05.20 [번역] 호스트배열 (Host Arrays) - 03
  4. 2015.05.20 [번역] 호스트배열 (Host Arrays) - 02
  5. 2015.05.20 [번역] 호스트배열 (Host Arrays) - 01
  6. 2015.05.20 [번역] Embedded PL/SQL - 04
  7. 2015.05.20 [번역] Embedded PL/SQL - 03
  8. 2015.05.20 [번역] Embedded PL/SQL - 02
  9. 2015.05.20 [번역] Embedded PL/SQL - 01
  10. 2015.05.20 [번역] Embedded SQL - 03

[Java] ClassLoader API

Language/JAVA 2016. 8. 4. 14:59

http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html


클래스를 로딩하는 책임을 지니고 있는 추상 클래스. 

기본전략: 바이너리 이름(String)을 받아서 파일 이름으로 바꾸고 파일 시스템에서 해당하는 이름의 클래스 파일을 읽어들인다.

위임 모델(delegation model)을 사용하여 클래스와 리소스를 찾는다. 각각의 ClassLoader 인스턴스는 연관된 상위(parent) 클래스 로더를 가지고 있다. 자신이 찾아 보기전에 상위 클래스 로더에 요청하여 먼저 찾아본다. VM 내장 클래스 로더인 "부트스트랩 클래스 로더"는 상위 클래스 로더가 없고 자신이 다른 ClassLoader 인스턴스의 상위가 된다.

보통 JVM은 플랫폼-독립적인 방식으로 로컬 파일 시스템에서 클래스를 읽어들인다. 예를 들어 유닉스 시스템에서 VM은 CLASSPATH 환경 변수에 정의되어 있는 디렉토리에서 클래스를 로딩한다.

하지만 어떤 클래스들은 파일에서 읽어오지 않고 네트워크에서 가져오거나 애플리케이션이 동작하면서 만들어지는 것도 있다. defineClass 메서드는 바이트 배열을 Class 클래스 인스턴스로 변환한다. Class.newInstance를 사용하여 그렇게 새로 정의된 클래스 인스턴스를 만들 수 있다.

클래스로더에 의해 만들어지는 객체의 메소드와 생성자는 다른 클래스를 참조할 수도 있다. 그렇게 참조하는 클래스들을 판단하기 위해 VM은 원래 클래스를 생성한 클래스 로더의 loadClass 메서드를 호출한다.

예를 들어 네트워크 클래스 로더를 만들어 다른 서버에서 클래스 파일을 다운로드 할 수도 있다. 다음은 예제 코드다.

ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();

네트워크 클래스 로더는 반드시 findClass와 네트워크에서 클래스를 읽어올 loadClassData를 정의해야한다. 바이트코드를 다운로드 한다음 defineClass를 사용하여 class 인스턴스를 만들어야 한다. 다음은 예제 구현체다.

     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }
 

바이너리 이름

클래스로더에 전달되는 문자열로 표현한 클래스 이름은 다음에 정의된 자바 언어 표준을 따라야 한다.

예)
   "java.lang.String"
   "javax.swing.JSpinner$DefaultEditor"
   "java.security.KeyStore$Builder$FileBuilder$1"
   "java.net.URLClassLoader$3$1"

defineClass

- protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError

바이트를 Class 클래스의 인스턴스로 변환한다. Class는 resolve를 한 다음에 사용해야 한다. 

loadClass

- public Class<?> loadClass(String name) throws ClassNotFountException

loadClass(naem, false); 호출

- public Class<?> loadClass(String name, boolean resolve) throws ClassNotFountException

기본 동작은 다음과 같다.
1. findLoadedClass(String)을 호출하여 클래스가 이미 로딩되었는지 확인한다.
2. 상위 클래스 로더의 loadClass 메서드를 호출한다. 만약 상위 클래스 로더가 null이면 VM 내장 클래스 로더를 사용한다.
3. findClass(String) 메서드를 사용하여 클래스를 찾는다.

만약에 위 과정을 통해 클래스를 찾은 뒤에 resolve 플래그가 true면 반환받은 Class 객체를 사용하여resolveClass(Class) 메서드를 호출한다.

클래스로더의 하위 클래스들은 이 메서드가 아니라 findClass(String)을 재정의 할 것을 권한다.
(이런걸 지켜야 리스코프 원칙을 지켰다고 하던가...)

findLoadedClass

- protected final Class<?> findLoadedClass(String name)

만약 이 클래스로더가 JVM에 initiating 로더로 기록되어 있다면 name에 해당하는 클래스를 반환한다. 그렇지 않으면 null을 반환한다.

findClass

- protected Class<?> findClass(String name) throws ClassNotFoundException

기본 구현체는 ClassNotFoundException을 던진다. 따라서 클래스 로더를 확장하는 클래스가 이것을 구현하여 delegation 모델을 따르는 구현체를 만드는데 사용해야 한다. loadClass 메서드에서 상위 클래스 로더를 확인 한 뒤에 호출된다.
(그냥 클래스만 찾으면 되지 꼭 delegation 모델을 따라야 하는건가... 사실 loadClass가 public이라 그것도 재정의하면 그만인것을. 강요하려면 하고 말려면 말지 어중간한거 아닌가..)

resolveClass

- protected final void resolveClass(Class<?> c)

해당 클래스를 링크한다. 이 메서드는 클래스 로더가 클래스를 링크할 때 사용된다. 만약 클래스 c가 이미 링크되어 있다면 이 메서드는 그냥 끝난다. 그렇지 않은 경우라면 자바 언어 스팩의 "Execution" 챕터에 기술되어 있는대로 클래스를 링크한다.

링크


링크하기(Linking)란 클래스 또는 인터페이스 타입의 바이너리를 가져와서 JVM의 런타임에 연결하여 실행 할 수 있는 상태로 만드는 것이다. 

링크 과정은 세 가지 세부 활동으로 구성된다: verification, preparation, resolution

링크 활동 구현내용은 달라질 수 있다. 예를 들어 클래스가 사용되는 순간에 개별적으로 클래스나 인터페이스에 있는 심볼릭 레퍼런스를 확정하거나(lazy or late resolution), 검증하고나서 바로 확정할 수도 있다.(static). 즉 어떤 구현체에서는 클래스나 인터페이스를 초기화 한 이후에도 확정(resolution) 프로세스가 계속 될 수 있다는 것이다.

Verification, Preparation, Resolution


Verification: 클래스나 인터페이스의 바이너리가 구조적으로 올바른지 확인한다. 검증에 실패하면LinkageError의 하위 클래스 중 하나인 VerifyError가 발생한다.

Preparation: 클래스나 인터페이스의 static 필드를 만들고 그런 필드들을 기본 값으로 초기화 하는 과정이 포함된다. 이 과정 중에 JVM 코드를 실행할 필요가 없다. 명시적인 static 필드 initializer는 이 과정이 아니라 initialization 과정에서 실행된다.

Resolution: 심볼릭 레퍼런스는 resolution단계를 지나야지 사용될 수 있다. 심볼릭 레퍼런스가 유효하고 반복적으로 사용되면 다이렉트 레퍼런스로 교체되어 보다 효율적으로 처리된다.

만약 이 단계를 지나다가 IncompatibleClassChangeError를 포함한 이 하위 에러들이 발생할 수 있다. IllegalAccessErrorInstantiationErrorNoSuchFieldErrorNoSuchMethodError

추가적으로 구현체를 찾을 수 없는 native 메서드를 선언한 클래스에서는 UnsatisfiedLinkError가 발생할 수 있다. 


출처 - http://whiteship.tistory.com/2560

:

[번역] 런타임 에러 처리 (Handling Runtime Errors)

Language/Pro*C 2015. 5. 20. 17:23

목 차
▣ The Need for Error Handling
▣ Error Handling Alternatives
▣ SQLSTATE 상태변수( The SQLSTATE Status Variable )
▣ SQLCODE선언( Declaring SQLCODE )
▣ Key Components of Error Reporting Using the SQLCA
▣ Using the SQL Communications Area (SQLCA)
▣ Getting the Full Text of Error Messages
▣ Using the WHENEVER Directive
▣ Obtaining the Text of SQL Statements
▣ Using the Oracle Communications Area (ORACA)

1) The Need for Error Handling
: 여러가지 상황에서 에러가 발생할 수 있기 때문에 에러 처리는 필요하며, 프로그램에
중요한 부분을 차지하게 된다.

2) Error Handling Alternatives
: Manual 참조
3) SQLSTATE 상태변수( The SQLSTATE Status Variable )
: Manual 참조

4) SQLCODE선언( Declaring SQLCODE )
: Manual 참조

5) Key Components of Error Reporting Using the SQLCA
: sqlcode -> 0 success, sqlcode -> - error, sqlcode-> + exception
warning flag는 sqlwarn[0]~sqlwarn[7]에 설정됨.
최근에 실행된 SQL문에서 리턴된 행수는 sqlca.sqlerrd[2]에 설정됨.

sqlca.sqlerrd[4]-> SQL문을 파싱하다가 에러가 발생하면 옵셋값을 설정.
파싱하다 에러가 난 지점의 문자위치를 옵셋에 설정(zero-based position)
에러가 발생하지 않으면,sqlca.sqlerrd[4]는 0이다. 첫번째문자에서 에러가 발생해도
sqlca.sqlerrd[4]에는 0이 설정된다. 그래서 sqlca.sqlerrd[4]는 sqlca.sqlcode가
음수로 리턴될때만 체크한다.

에러코드와 메세지는 SQLERRMC인 SQLCA변수에 저장되며 길이는 70문자가 저장된다.
70문자 이상의 TEXT를 보기위해서는 sqlglm()함수를 사용한다.

6) Using the SQL Communications Area (SQLCA)
: MODE=ORACLE인 경우, SQLCA선언이 필요하며,선언하기 위해서는 아래와 같이 하면된다.
EXEC SQL INCLUDE SQLCA;
혹은
#include <sqlca.h>

Declare Section을 사용하면, SQLCA는 Declare Section 밖에 선언되어야만 한다.
SQLCA를 선언하지 않으면 컴파일시 에러가 난다.

MODE=ANSI인경우, SQLCA선언은 선택적이면, SQLCODE혹은 SQLSTATE 상태변수는 반드시 선언
해야만 한다. SQLCODE는 int형이다. SQLCA 대신에 SQLCODE혹은 SQLSTATE를 선언하고 컴파일
할 경우, 전처리기는 내부적으로 SQLCA를 할당한다. Pro*C/C++프로그램은 내부적인 SQLCA를
접근할 수 없다.

6-1) SQLCA Contents
: SQLCA는 다음과 같은 내용을 포함하고 있다.
# 오라클 에러코드
# 경고 플래그들 (Warning flags)
# 이벤트 정보
# 처리된 행의 수
# 분석 (Diagnostics)

sqlca.h 헤더 파일에 대해서 살펴보자.

/*
이름 : SQLCA = SQL Communications Area.
기능 : 코드 내용은 없다. 오라클은 sql문이 실행되는동안 sqlca에
상태정보를 채운다.
NOTES
**************************************************************
*** ***
*** This file is SOSD. Porters must change the data types ***
*** appropriately on their platform. See notes/pcport.doc ***
*** for more information. ***
*** ***
**************************************************************
If the symbol SQLCA_STORAGE_CLASS is defined, then the SQLCA
will be defined to have this storage class. For example:
#define SQLCA_STORAGE_CLASS extern
will define the SQLCA as an extern.
If the symbol SQLCA_INIT is defined, then the SQLCA will be
statically initialized. Although this is not necessary in order
to use the SQLCA, it is a good programing practice not to have
unitialized variables. However, some C compilers/operating systems
don't allow automatic variables to be initialized in this manner.
Therefore, if you are INCLUDE'ing the SQLCA in a place where it
would be an automatic AND your C compiler/operating system doesn't
allow this style of initialization, then SQLCA_INIT should be left
undefined -- all others can define SQLCA_INIT if they wish.
If the symbol SQLCA_NONE is defined, then the SQLCA
variable will not be defined at all. The symbol SQLCA_NONE
should not be defined in source modules that have embedded SQL.
However, source modules that have no embedded SQL, but need to
manipulate a sqlca struct passed in as a parameter, can set the
SQLCA_NONE symbol to avoid creation of an extraneous sqlca variable.
*/
#ifndef SQLCA
#define SQLCA 1
struct sqlca
{
/* ub1 */ char sqlcaid[8]; //SQLCA로 초기화된다.
/* b4 */ long sqlabc; //SQLCA구조체의 길이(바이트)
/* b4 */ long sqlcode; //최근실행된 상태코드 [ 0 : 성공, >0 : exception
MODE=ANSI인경우, +100은 INSERT후에 입력된 행이 없음
<0 은 어떤 ERROR때문에 SQL문을 실행할 수 없을때 발생.
이경우 모든 트랜잭션은 롤백된다.

struct
{
/* ub2 */ unsigned short sqlerrml; // sqlerrmc의 메세지 길이
/* ub1 */ char sqlerrmc[70]; // 에러코드에 상응하는 메세지(not null terminate)
} sqlerrm; // 70문자까지 저장될 수 있음
// 70문자 이상의 경우 sqlglm()함수 사용
/* ub1 */ char sqlerrp[8]; // 미래를 위해서 예약된 변수
/* b4 */ long sqlerrd[6]; // sqlerrd[0] -> 미래를 위해 예약된 변수
// sqlerrd[1] -> 미래를 위해 예약된 변수
// sqlerrd[2] -> 최근에 실행된 SQL문의 처리 행수
SQL문이 실패하면, 정의되지 않음
처리행수는 OPEN문후에 0이되고, FETCH
후에 증가한다.
// EXCUTE,INSERT,UPDATE,DELETE,SELECT문에서 성공적으로
처리된 행수를 반영,UPDATE,DELETE CASCADE에 의해서
처리된 행수는 포함하지 않음.
// sqlerrd[3] -> 미래를 위해 예약된 변수
// sqlerrd[4] -> 최근에 실행된 SQL문의 파싱에러가 난
문자위치의 OFFSET저장.
// sqlerrd[5] -> 미래를 위해 예약된 변수
/* ub1 */ char sqlwarn[8];
// sqlwarn[0] -> 다른 warning flag가 설정되면, 이 요소가 설정
// sqlwarn[1] -> 잘려진 컬럼값이 호스트변수에 할당되었을때 설정
// sqlwarn[2] -> NULL컬럼이 sql 그룹함수에서 사용되지 않는경우 설정
// sqlwarn[3] -> 쿼리의 컬럼수와 select나 fetch문의 into절에 호스트변수의 수가 틀릴
경우 설정
// sqlwarn[4] -> 사용되지 않음
// sqlwarn[5] -> EXEC SQL CREATE {PROCEDURE |FUNCTION | PACKAGE | PACKAGE BODY}문
이 pl/sql 컴파일 에러 때문에 실패했을때 설정.
// sqlwarn[6] -> 사용되지 않음
// sqlwarn[7] -> 사용되지 않음
/* ub1 */ char sqlext[8]; // 미래를 위해 예약된 변수
};

#ifndef SQLCA_NONE
#ifdef SQLCA_STORAGE_CLASS
SQLCA_STORAGE_CLASS struct sqlca sqlca
#else
struct sqlca sqlca
#endif
#ifdef SQLCA_INIT
= {
{'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '},
sizeof(struct sqlca),
0,
{ 0, {0}},
{'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
}
#endif
;
#endif
#endif

6-2) PL/SQL 고려사항
: 내부에 포함된 PL/SQL블록을 실행할때 SQLCA의 요소는 설정되지 않는다.
만약 블록이 여러행을 FETCH한다면, sqlerrd[2]는 단지 1로 설정되어 있을 것이다.
PL/SQL블록 실행후 SQLCA의 요소는 sqlcode와 sqlerrm에 의존해야만 한다.

7) Getting the Full Text of Error Messages
: 70문자 이상의 에러메세지를 취득해야 할 경우 아래의 함수를 사용한다.
void sqlglm(char *message_buffer,
size_t *buffer_size,
size_t *message_length);

==============================================================================
문법 설명
------------------------------------------------------------------------------
message_buffer 에러메세지를 저장하기위한 버퍼
buffer_size 버퍼의 최대값을 지정하는 변수(바이트단위)
message_length 에러메세지의 실제길이를 저장
==============================================================================
아래의 예제는 200바이트 문자까지 에러메세지를 얻기위해서 sqlglm()함수를 사용하는
예제를 보여주고 있다.

EXEC SQL WHENEVER SQLERROR DO sql_error();
...
/* other statements */
...
sql_error()
{
char msg[200];
size_t buf_len, msg_len;
buf_len = sizeof (msg);
sqlglm(msg, &buf_len, &msg_len); /* note use of pointers */
printf("%.*snn", msg_len, msg);
exit(1);
}

위의 함수를 사용하기전에 SQLCODE가 0이 아닌경우를 먼저체크 하고 사용해야한다.
만약에 SQLCODE가 0인경우 sqlglm()함수를 호출하면 이전 SQL문과 관련된 메세지를 얻게된다.

8) Using the WHENEVER Directive
: 상황체크나 에러처리를 자동으로 하기위해서는 WHENEVER 명령(지시자)가 필요한다.
아래와 같은 문법으로 사용한다.

EXEC SQL WHENEVER <condition> <action>;

<condition>
SQLWARNING : sqlwarn[0]은 오라클이 경고를 리턴했을때 혹은 SQLCODE가 1043이 아닌 다른
양의 정수값을 가질때 설정된다. 예를 들어 오라클은 호스트 변수에 잘려진
컬럼값을 할당할때 설정한다.
SQLERROR : SQLCODE는 오라클이 에러를 리턴하기때문에 음수값을 가진다.
NOT FOUND : SQLCODE는 1043값을 가진다. MODE=ANSI인경우 100을 리턴한다.

<action>
CONTINUE : 다음 문장을 계속해서 실행할때 사용한다.
DO : 에러처리 함수로 제어를 넘긴다.
DO BREAK : LOOP와 같은 행위를 할때, LOOP를 빠져나가는 행위를 한다.
GOTO label_name : label_name명으로 넘어간다. label_name명은 31문자를 기본으로 한다.
STOP : 작동을 멈추고, commit되지 않은 작업은 Roll Back된다.

8-1) WHENEVER 예제
: 아래에는 WHENEVER 예제를 보여주고 있다.
EXEC SQL WHENEVER NOT FOUND GOTO close_cursor;
EXEC SQL WHENEVER SQLWARNING CONTINUE;
EXEC SQL WHENEVER SQLERROR GOTO error_handler;
==========================================================================
'no data found'상태가 일어나면, close_cursor로 간다.
warning이 발생하면, 다음 문장을 계속한다.
error가 발생하면, error_handler로 간다.
--------------------------------------------------------------------------
...
EXEC SQL WHENEVER SQLERROR DO handle_insert_error("INSERT error");
EXEC SQL INSERT INTO emp (empno, ename, deptno)
VALUES (:emp_number, :emp_name, :dept_number);

EXEC SQL WHENEVER SQLERROR DO handle_delete_error("DELETE error");
EXEC SQL DELETE FROM dept WHERE deptno = :dept_number;
...

handle_insert_error(char *stmt)
{
switch(sqlca.sqlcode)
{
case -1:
/* duplicate key value */
...
break;
case -1401:
/* value too large */
...
break;
default:
/* do something here too */
...
break;
}
}

handle_delete_error(char *stmt)
{
printf("%snn", stmt);
if (sqlca.sqlerrd[2] == 0)
{
/* no rows deleted */
...
}
else
{
...
}
...
}

8-2) DO BREAK와 DO CONTINUE 의 사용
: 아래의 예제는 사원 이름, 봉급, 임무를 어떻게 표시하는지 보여주고 있다.
#include <sqlca.h>
#include <stdio.h>

main()
{
char *uid = "scott/tiger";
struct { char ename[12]; float sal; float comm; } emp;
/* 연결시 에러가 발생하면 whoops로 이동 */
EXEC SQL WHENEVER SQLERROR GOTO whoops;
EXEC SQL CONNECT :uid;
EXEC SQL DECLARE c CURSOR FOR
SELECT ename, sal, comm FROM EMP ORDER BY ENAME ASC;
EXEC SQL OPEN c;
/* 데이터가 없으면, 'BREAK'처리 */
EXEC SQL WHENEVER NOT FOUND DO BREAK;
/* 에러가 발생하면, 다음 처리를 위해 loop의 처음으로 이동한다. */
EXEC SQL WHENEVER SQLERROR DO CONTINUE;
while (1)
{
EXEC SQL FETCH c INTO :emp;
/* ORA-1405는 'continue'되고. 값이 있는 commission인경우만 표시 */
printf("%s %7.2f %9.2fn", emp.ename, emp.sal, emp.comm);
}

/* This 'CONTINUE' shuts off the 'DO CONTINUE' allowing the program to
proceed if any further errors do occur, specifically, with the CLOSE */

EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL CLOSE c;
exit(EXIT_SUCCESS);
whoops:
printf("%.*sn", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
exit(EXIT_FAILURE);
}

8-3) WHENEVER의 범위
: WHENEVER의 범위는 위치에 따라서 틀려진다. 아래의 예제를 보자
step1:
EXEC SQL WHENEVER SQLERROR STOP;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
...
goto step3;
step2:
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL UPDATE emp SET sal = sal * 1.10;
...
step3:
EXEC SQL DROP INDEX emp_index;

위의 예제는 WHENEVER SQLERROR 지시자는 두번째에 의해서 대체된다. 그래서 단지 CONNECT
문장에서만 적용된다. 두번째 WHENEVER SQLERROR 지시자는 STEP1에서 STEP3로 제어가 넘어
가더라도 UPDATE와 DROP문 두개다 적용된다.

8-4) WHENEVER 가이드라인
: 아래의 가이드 라인은 일반적인 함정을 피할 수 있도록 도울 것이다.

문장위치
: 처음 SQL문 전에 WHENEVER지시자를 적으면, 파일의 끝까지 영향을 미친다.

End-of-Data Condition처리
: 아래의 예제 처럼 처리한다.

EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH...
}
EXEC SQL CLOSE my_cursor;
...
위의 경우는 Fetch해서 데이터가 없는경우 프로그램을 멈추는 처리이다.
EXEC SQL WHENEVER NOT FOUND DO break;
for(;;)
{
EXEC SQL FETCH ...
EXEC SQL WHENEVER NOT FOUND CONTINUE;
EXEC SQL INSERT INTO ...
}
EXEC SQL CLOSE my_cursor;
...
위의 경우는 insert될 데이터가 없다고 하더라고 계속해서 작업을 진행하는 처리이다.

무한반복 피하기
: 무한 루프를 피하기 위한 방법을 아래의 예제에서 보여주고 있다.

EXEC SQL WHENEVER SQLERROR GOTO sql_error;
...
sql_error:
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
...
에러처리전에 EXEC SQL WHENEVER SQLERROR CONTINUE;문을 사용하여 무한 루프를 방지한다.

/* 적당하지 않은 WHENEVER의 사용 */
...
EXEC SQL WHENEVER NOT FOUND GOTO no_more;
for (;;)
{
EXEC SQL FETCH emp_cursor INTO :emp_name, :salary;
...
}
no_more:
// Not Found인 경우 무한루프를 돌기때문에 아래의 처리를 반드시 해야한다.
EXEC SQL WHENEVER NOT FOUND GOTO no_match;
EXEC SQL DELETE FROM emp WHERE empno = :emp_number;
...
no_match:
...

주소 유지
: 아래 예제의 경우 에러가 발생한다. 원인은 func2함수내의 insert문의
범위내에 func1에 있는 labelA가 없기때문이다.
func1()
{
EXEC SQL WHENEVER SQLERROR GOTO labelA;
EXEC SQL DELETE FROM emp WHERE deptno = :dept_number;
...
labelA:
...
}

func2()
{
EXEC SQL INSERT INTO emp (job) VALUES (:job_title);
...
}

WHENEVER GOTO문으로 분기되는 label은 전처리 파일에서 선언되어야만 한다.

에러후의 리턴
: 에러처리후에 리턴되어야 한다면, DO routine_call을 사용한다.
선택적으로, 아래의 예처럼 sqlcode값을 비교할 수 있다.
...

EXEC SQL UPDATE emp SET sal = sal * 1.10;

if (sqlca.sqlcode < 0)
{
/* handle error */

EXEC SQL DROP INDEX emp_index;

9) Obtaining the Text of SQL Statements
: SQLStmtGetText() 함수 (예전이름 : sqlgls() 함수)는 아래의 정보를 리턴한다.
# 최근에 파싱된 SQL문의 TEXT
# 문장의 유효한 길이
# SQL명령에 대한 함수 코드

SQLStmtGetText()의 prototype은 아래와 같다.

void SQLStmtGetText(dvoid *context, char *sqlstm, size_t *stmlen, size_t *sqlfc);

<context>
런타임 context이다. "CONTEXT변수" 참조.
<sqlstm>
sql문장을 리턴하는 문자버퍼.
<stmlen>
sqlstm버퍼의 실제 크기(바이트) 설정.
<sqlfc>
SQL명령의 함수 코드.
함수코드에 대한 내용은 [Table 9-3]을 참조한다.





에러가 발생하면 stmlen은 0을 리턴한다. 에러가 발생할 수 있는 상태는 아래와 같다.

# SQL문이 파싱되지 않은경우
# 유효하지 않은 파라미터를 넘겼을경우
# SQLLIB에서 내부적인 예외가 발생했을 경우

9-1) 제한사항
: 아래의 명령이 포함된 문장은 SQLStmtGetText()함수에 리턴되지 않는다.
# CONNECT
# COMMIT
# ROLLBACK
# FETCH
위의 명령에 대해서는 SQL 함수코드가 존재하지 않는다.

10) Using the Oracle Communications Area (ORACA)
: SQLCA에서 제공하는것보다 많은 런타임 에러나 상태변경 정보를 원한다면 ORACA를 사용한다.
ORACA는 오라클 리소스(RESOURCE)의 사용을 모니터링 한다.

10-1) ORACA 선언
: ORACA를 선언하기 위해서는 아래와 같이 선언한다.

EXEC SQL INCLUDE ORACA;
or
#include <oraca.h>

프로그램에서 Declare Section을 사용한다면 , ORACA는 그것 밖에 선언 되어야만 한다.
10-2) ORACA 내용
: ORACA는 옵션설정,시스템통계를 포함하며
# SQL문장
# 에러가 발생한 파일이름
# 파일에서 에러의 위치
# 커서 캐쉬와 통계
의 확장 분석을 포함한다.

아래는 oraca.h의 부분 내용이다.
======================================================================================
/*
NAME
ORACA : Oracle Communications Area.
If the symbol ORACA_NONE is defined, then there will be no ORACA
*variable*, although there will still be a struct defined. This
macro should not normally be defined in application code.
If the symbol ORACA_INIT is defined, then the ORACA will be
statically initialized. Although this is not necessary in order
to use the ORACA, it is a good pgming practice not to have
unitialized variables. However, some C compilers/operating systems
don't allow automatic variables to be init'd in this manner. Therefore,
if you are INCLUDE'ing the ORACA in a place where it would be
an automatic AND your C compiler/operating system doesn't allow this style
of initialization, then ORACA_INIT should be left undefined --
all others can define ORACA_INIT if they wish.
*/
#ifndef ORACA
#define ORACA 1
struct oraca
{
char oracaid[8]; /* 예약변수 */
long oracabc; /* 예약변수 */
/* 사용자에의해서 설정될 수 있는 Flags */
long oracchf; /* <> 0 if "check cur cache consistncy"*/
long oradbgf; /* <> 0 if "do DEBUG mode checking" */
long orahchf; /* <> 0 if "do Heap consistency check" */
long orastxtf; /* SQL stmt text flag */

#define ORASTFNON 0 /* = don't save text of SQL stmt */
#define ORASTFERR 1 /* = only save on SQLERROR */
#define ORASTFWRN 2 /* = only save on SQLWARNING/SQLERROR */
#define ORASTFANY 3 /* = always save */

struct
{
unsigned short orastxtl;
char orastxtc[70];
} orastxt; /* text of last SQL stmt */

struct
{
unsigned short orasfnml;
char orasfnmc[70];
} orasfnm; /* name of file containing SQL stmt */

long oraslnr; /* line nr-within-file of SQL stmt */
long orahoc; /* highest max open OraCurs requested */
long oramoc; /* max open OraCursors required */
long oracoc; /* current OraCursors open */
long oranor; /* nr of OraCursor re-assignments */
long oranpr; /* nr of parses */
long oranex; /* nr of executes */
};
#ifndef ORACA_NONE
#ifdef ORACA_STORAGE_CLASS
ORACA_STORAGE_CLASS struct oraca oraca
#else
struct oraca oraca
#endif
#ifdef ORACA_INIT
=
{
{'O','R','A','C','A',' ',' ',' '},
sizeof(struct oraca),
0,0,0,0,
{0,{0}},
{0,{0}},
0,
0,0,0,0,0,0
}
#endif
;
#endif
#endif
/* end oraca.h */



출처 - http://younbok.egloos.com/9342715

:

[번역] 호스트배열 (Host Arrays) - 03

Language/Pro*C 2015. 5. 20. 17:22

목 차
▣ 왜 배열을 사용하는가?
▣ 호스트 배열의 선언
▣ SQL문에서의 배열사용
▣ 배열로 Select하기
▣ 배열과 Insert하기
▣ 배열과 Update하기
▣ 배열과 Delete하기
▣ FOR절 사용
▣ WHERE절 사용
▣ 배열 구조체
▣ Mimicking CURRENT OF

8) FOR절 사용
: DELETE,EXECUTE,FETCH,INSERT OPEN UPDATE문의 의해서 처리되는 배열의 크기를
설정하기위해서 FOR절을 사용할 수 있다.
FOR절은 특히 UPDATE,INSERT,DELETE문에서 특히 유용하게 사용될 수 있다.
이런문을 사용할때 전체배열크기를 사용하기를 원하지 않을경우 FOR절은 사용할
크기를 제한 할 수 있다. 아래에 예제에서 이를 보여주고 있다.

char emp_name[100][20];
float salary[100];
int rows_to_insert;
/* 호스트 배열을 채운다. */
rows_to_insert = 25; /* FOR절 변수를 설정 */
EXEC SQL FOR :rows_to_insert /* 25개행을 처리할 것이다. */
INSERT INTO emp (ename, sal)
VALUES (:emp_name, :salary);

아래의 예제는 허용되지 않는 표현으로 FOR절을 설정한 경우이다.
EXEC SQL FOR :rows_to_insert + 5 /* illegal */
INSERT INTO emp (ename, empno, sal)
VALUES (:emp_name, :emp_number, :salary);

8-1) FOR절에대한 제한사항
: SELECT문에서 FOR절 혹은 CURRENT OF절과 함께 사용할 수는 없다.
8-1-1) SELECT 문에서의 사용
: SELECT문에서 FOR절을 사용하면, 에러메세지를 얻는다.
그것의 의미가 불분명하기때문에 FOR절은 SELECT문에 허용되는 않는다.
"SELECT문을 n번 실행할 것인가?" 혹은 "SELECT문을 한번 실행하고 n개 행을 얻을
것인가?"하는 두가지 의미로 해석될 수 있다.
전자는 각실행이 여러행을 리턴할 경우이며, 후자의 경우는, 커서를 선언하여 사용
하는것이 낮고 FETCH문에 FOR절을 사용하는 예제는 아래와같다 :

EXEC SQL FOR :limit FETCH emp_cursor INTO ...

8-1-2) CURRENT OF절과 함께 사용
: 아래의 예제는 FETCH문에의해서 리턴된 최근의 행을 참조하기위해서 UPDATE/
DELETE문에서 CURRENT OF 절을 사용할 수는 예제이다.

EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ename, sal FROM emp WHERE empno = :emp_number;
...
EXEC SQL OPEN emp_cursor;
...
EXEC SQL FETCH emp_cursor INTO :emp_name, :salary;
...
EXEC SQL UPDATE emp SET sal = :new_salary
WHERE CURRENT OF emp_cursor;

그러나,CURRENT OF 절과 FOR절을 함께 사용할 수 없다.
아래의 문장은 유효하지 않은 예이다.

EXEC SQL FOR :limit UPDATE emp SET sal = :new_salary
WHERE CURRENT OF emp_cursor;
...

EXEC SQL FOR :limit DELETE FROM emp
WHERE CURRENT OF emp_cursor;

9) WHERE절의 사용
: 오라클은 n개의 배열크기를 가진 호스트 배열이 포함된 SQL문을 SQL이 n번 실행되어야
한다고 처리한다. 하지만 전처리기는 의미가 모호할 경우 에러 메세지를 발생시킨다.
예를들어, 아래의 선언이 있다고 가정해보자.
int mgr_number[50];
char job_title[50][20];
EXEC SQL SELECT mgr INTO :mgr_number FROM emp
WHERE job = :job_title;

위의 문장은 아래의 문장으로 간주된다.

for (i = 0; i < 50; i++)
SELECT mgr INTO :mgr_number[i] FROM emp
WHERE job = :job_title[i];

여러행이 WHERE절에 만나게 되기 때문에 에러 메세지가 발생하게 된다.

반면, 아래의 문은 모호하지 않다.

EXEC SQL UPDATE emp SET mgr = :mgr_number
WHERE empno IN (SELECT empno FROM emp
WHERE job = :job_title);

위의 문장은 아래의 문 처럼 처리한다.

for (i = 0; i < 50; i++)
UPDATE emp SET mgr = :mgr_number[i]
WHERE empno IN (SELECT empno FROM emp
WHERE job = :job_title[i]);

10) 배열 구조체
: 배열구조체는 여러컬럼을 포함하는 한행 연산을 처리할 수 있도록 해준다.
10-1) 배열구조체 사용시 제한사항
- PL/SQL Block내에서는 사용 불가
- WHERE,FROM 절에 사용불가
- UPDATE문의 SET절에 사용불가
10-2) PRO*C/C++에서 배열구조체 사용시 유의 사항
- 구조체 TAG을 반드시 선언해서 사용할것
- 구조체의 MEMBER는 CHAR과 VARCHAR을 제외하고 배열이 있어서는 않된다.
- CHAR나 VARCHAR는 다자원배열을 사용할 수 없다.

아래의 예제는 사용할 수 없는 경우의 선언이다.

struct { /* 구조체 tag이 선언되지 않음 */
int empno[15]; /* 구조체 member는 배열이 될 수 없음 */
char ename[15][10]; /* CHAR는 2차원 배열이 될 수 없다 */
struct nested {
int salary; /* 구조체 배열에 구조체가 사용될 수 없다 */
} sal_struct;
} bad[15];

아래의 예제는 배열이 합법적인 것과 비합법적인것을 보여주고 있다.

int empno[15];
exec sql var empno[3] is integer(4); /* illegal */
myint empno[15]; /* legal */

10-3) 배열구조체의 포인터 선언
: 몇몇의 경우에는 배열구조체의 포인터를 선언해서 사용해야 바람직한 경우가
있다. 직접적으로 SQL문에 사용하는 경우나 혹은 다른 함수에 인자로 넘기는
경우 배열 포인터를 사용 할 수 있다.

SELECT문에 FOR절을 사용할 수 없기때문에, 구조체배열 포인터에 값을 추출하기
위해서 명시적인 커서,FETCH문이 FOR절에 사용되어야만 한다.

10-4) 예제
: 아래와같이 구조체를 선언한다.

struct department {
int deptno;
char dname[15];
char loc[14];
} my_dept[4];

위의 구조체를 이용해서 다음과 같이 사용할 수 있다.

exec sql select * into :my_dept from dept;

exec sql insert into dept values (:my_dept);

지시자 변수를 사용하기위해서 아래와 같은 구조체를 선언해서 사용할 수 있다.

struct deptartment_ind {
short deptno_ind;
short dname_ind;
short loc_ind;
} my_dept_ind[4];

지시자변수의 사용법은 아래와 같다.

exec sql select * into :my_dept indicator :my_dept_ind from dept;
exec sql insert into dept values (:my_dept indicator :my_dept_ind);

배열구조체와 SCALAR ARRAY(첨자가숫자로 주어지는 배열)의 혼용예제를
살펴보자.
구조체와 SCALAR ARRAY를 아래와 같이 선언한다.

struct employee {
int empno;
char ename[11];
} emp[14];

float sal[14];
float comm[14];

위와같이 혼용하기위해서는 SCALARY ARRAY와 구조체 배열의 크기가 같아야한다.
SELECT시 예제는 아래와 같다.

exec sql select empno, ename, sal, comm into :emp, :sal, :comm from emp;

지시자의 선언은 아래와 같이 사용하면 된다.

short comm_ind[14];
...

exec sql select empno, ename, sal, comm
into :emp, :sal, :comm indicator :comm_ind from emp;

커서를 사용한 여러개의 구조체 배열사용예에 대해서 살펴보자.

예를 들어, 아래와 같이 구조체가 선언되어 있다고 가정하자.

struct employee {
int empno;
char ename[11];
char job[10];
} emp[14];

struct compensation {
int sal;
int comm;
} wage[14];

struct compensation_ind {
short sal_ind;
short comm_ind;
} wage_ind[14];

위의 구조체를 사용하는 예제는 다음과 같다.

exec sql declare c cursor for
select empno, ename, job, sal, comm from emp;

exec sql open c;
exec sql whenever not found do break;
while(1)
{
exec sql fetch c into :emp, :wage indicator :wage_ind;

... process batch rows returned by the fetch ...
}

printf("%d rows selected.n", sqlca.sqlerrd[2]);

exec sql close c;

다음으로 구조체 포인터에 대해서 사용하는 예를 살펴 보도록 하자.
아래와 같이 구조체를 선언한다.

typedef struct dept {
int deptno;
char dname[15];
char loc[14];
} dept;

아래의 예제는 함수에 인자로 구조체배열포인터를 넘겨 처리하는 과정을
보여주고 있다.

void insert_data(d, n)
dept *d;
int n;
{
exec sql for :n insert into dept values (:d);
}
void fetch_data(d, n)
dept *d;
int n;
{
exec sql declare c cursor for select deptno, dname, loc from dept;
exec sql open c;
exec sql for :n fetch c into :d;
exec sql close c;
}

위의 함수는 아래의 예처럼 사용할 수 있다.

dept d[4];
dept *dptr = &d[0];
const int n = 4;
fetch_data(dptr, n);
insert_data(d, n); /* We are treating ’&d[0]’ as being equal to ’d’ */

구조체배열 포인터에 정보를 취득하기위해서 아래와 같이 사용할 수 있다.

exec sql for :n insert into dept values (:dptr);

위의 문장에서 가장 중요한 것은 FOR절의 사용임을 명심해야한다.

11) Mimicking CURRENT OF(CURRENT OF의 모방(?) )
: 커서를 사용해서 FETCH한 최근의 행에서 UPDATE나 DELETE에 CURRENT OF CURSOR절을
사용한다. 그라나 호스트배열과 CURRENT OF 절은 사용할 수 없으며 대신, 각행의
ROWID를 선택하고, UPDATE나 DELETE하는 동안 현재행을 인식하기위해서 그값을 사용할
수 있다.
예제를 보면 다음과 같다.
char emp_name[20][10];
char job_title[20][10];
char old_title[20][10];
char row_id[20][19];
...
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ename, job, rowid FROM emp;
...
EXEC SQL OPEN emp_cursor;
EXEC SQL WHENEVER NOT FOUND do break;
for (;;)
{
EXEC SQL FETCH emp_cursor
INTO :emp_name, :job_title, :row_id;
...
EXEC SQL DELETE FROM emp
WHERE job = :old_title AND rowid = :row_id;
EXEC SQL COMMIT WORK;
}
그러나 FETCH된 행은 FOR UPDATE OF 절이 사용되지 않았기 때문에 LOCK이 걸리지 않는다.
(CURRENT OF없이 FOR UPDATE OF절을 사용할 수 없다.) 그래서 정보에 대해서 일치되지
않은 결과를 얻을 수 도 있다.



출처 - http://younbok.egloos.com/9342716

:

[번역] 호스트배열 (Host Arrays) - 02

Language/Pro*C 2015. 5. 20. 17:21
목 차
▣ 왜 배열을 사용하는가?
▣ 호스트 배열의 선언
▣ SQL문에서의 배열사용
▣ 배열로 Select하기
▣ 배열과 Insert하기
▣ 배열과 Update하기
▣ 배열과 Delete하기
▣ FOR절 사용
▣ WHERE절 사용
▣ 배열 구조체
▣ Mimicking CURRENT OF

4) 배열로 select하기
: select 문장에서 출력변수로 호스트배열을 사용할 수 있다. 아래의 예제는 select시 리턴되는 행
의 수를 알고 있을 경우 배열을 선언하고 사용하는 예제이다.
char emp_name[50][20];
int emp_number[50];
float salary[50];
EXEC SQL SELECT ENAME, EMPNO, SAL
INTO :emp_name, :emp_number, :salary
FROM EMP
WHERE SAL > 1000;
위의 예제에서와는 반대로 50개 이상의 행이 리턴 되는 경우는 더 큰 배열을 선언하던지 아니면
FETCH문을 사용하기 위해서 커서를 선언해야만 한다.
4-1) 커서 Fteches
: SELECT시 리턴될 행의 수를 알지 못할 경우, 아래와 같이 작성하면 된다. 아래의 예제의 경우
20개의 행을 각 FETCH시 마다 리턴해주는 예제이다.
int emp_number[20];
float salary[20];
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT empno, sal FROM emp;
EXEC SQL OPEN emp_cursor;
EXEC SQL WHENEVER NOT FOUND do break;
for (;;)
{
EXEC SQL FETCH emp_cursor
INTO :emp_number, :salary;
/* process batch of rows */
...
}
...
마지막 FETCH 작업 시에 실제적으로 리턴된 행수가 몇인지 체크하는 것을 잊지 마라.
4-2) sqlca.sqlerrd[2]의 사용
: insert,update,delete,select into 문에서 sqlca.sqlerrd[2]는 처리된 행수를 나타내고,
fetch문에 대해서는 처리된 행의 합계를 나타낸다.
fetch와함께 호스트 배열을 사용할 때 가장 최근의 반복에서 리턴된 행수를 구하려면,
이전값에서 현재 sqlca.sqlerrd[2]값을 빼야한다. 아래의 예제는 가장최근의 fetch에 의해
리턴된 행의 수를 결정하는 예제이다.
int emp_number[100];
char emp_name[100][20];
int rows_to_fetch, rows_before, rows_this_time;
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT empno, ename
FROM emp
WHERE deptno = 30;
EXEC SQL OPEN emp_cursor;
EXEC SQL WHENEVER NOT FOUND CONTINUE;
/* initialize loop variables */
rows_to_fetch = 20; /* number of rows in each "batch" */
rows_before = 0; /* previous value of sqlerrd[2] */
rows_this_time = 20;
while (rows_this_time == rows_to_fetch)
{
EXEC SQL FOR :rows_to_fetch
FETCH emp_cursor
INTO :emp_number, :emp_name;
rows_this_time = sqlca.sqlerrd[2] - rows_before;
rows_before = sqlca.sqlerrd[2];
}
...
배열연산을 하는 동안 에러가 발생했을 때 sqlca.sqlerrd[2]는 유용하게 사용된다. 처리과정중에
에러가 발생한 행에 멈추게 되며, sqlerrd[2]는 성공적으로 처리된 행의 수를 가지게 된다.
4-3) Fetch된 행수
: 각 fetch는 배열크기만큼 리턴을 한다. 아래의 경우는 배열크기보다 적은 행수가 리턴되는
경우이다.
# 리턴된 데이터가 없는경우 ‘no data found’가 리턴된 경우라고 보면된다.
# select시 리턴 받는 총 행수가 배열의 크기보다 적은 수를 리턴하는 경우이다.
# 행을 처리하는 동아 에러가 감지된 경우 fetch가 실패하고 오라클에서 에러코드를 리턴한다.
아래의 예제를 보면 리턴된 행의 수를 알 수 있다.
EXEC SQL OPEN cursor1;
EXEC SQL OPEN cursor2;
EXEC SQL FETCH cursor1 INTO :array_of_20;
/* now running total in sqlerrd[2] is 20 */
EXEC SQL FETCH cursor2 INTO :array_of_30;
/* now running total in sqlerrd[2] is 30, not 50 */
EXEC SQL FETCH cursor1 INTO :array_of_20;
/* now running total in sqlerrd[2] is 40 (20 + 20) */
EXEC SQL FETCH cursor2 INTO :array_of_30;
/* now running total in sqlerrd[2] is 60 (30 + 30) */
4-4) Sample Program 3: Host Array
: 아래의 데모 프로그램은 Pro*C/C++에서 쿼리를 작성할 때 호스트배열을 어떻게 사용하는지
보여주고 있다.
/*
* sample3.pc
* 호스트 배열
* 이 프로그램은 오라클에 연결하고, 커서를 선언하고 커서를 연후, 배열에 fetch를 하고
* 결과를 print_rows()라는 함수를 사용하여 표시한다.
*/
#include <stdio.h>
#include <string.h>
#include <sqlca.h>
#define NAME_LENGTH 20
#define ARRAY_LENGTH 5
/* 오라클 연결의 다른 방법 */
char *username = "SCOTT";
char *password = "TIGER";
/* 호스트 구조체 tag 선언 */
struct
{
int emp_number[ARRAY_LENGTH];
char emp_name[ARRAY_LENGTH][NAME_LENGTH];
float salary[ARRAY_LENGTH];
} emp_rec;
/* 함수선언 */
void print_rows(); /* 프로그램 출력처리 */
void sql_error(); /* 에러처리 */
main()
{
int num_ret; /* 리턴되는 행 수 */
/* ORACLE 연결 */
EXEC SQL WHENEVER SQLERROR DO sql_error("Connect error:");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("nConnected to ORACLE as user: %sn", username);
EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error:");
/* FETCH를 위해 커서 선언 */
EXEC SQL DECLARE c1 CURSOR FOR
SELECT empno, ename, sal FROM emp;
EXEC SQL OPEN c1;
/* 행수 초기화 */
num_ret = 0;
/* 배열 fetch 반복 ( NOT FOUND가 참이 되었을 때 ) */
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH c1 INTO :emp_rec;
/* 행수를 출력 */
print_rows(sqlca.sqlerrd[2] - num_ret);
num_ret = sqlca.sqlerrd[2]; /* 행수를 재설정 */
}
/* 마지막 fetch후 남은 행수를 출력 */
if ((sqlca.sqlerrd[2] - num_ret) > 0)
print_rows(sqlca.sqlerrd[2] - num_ret);
EXEC SQL CLOSE c1;
printf("nAu revoir.nnn");
/* 연결 종료 */
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
/* 행수 출력함수 */
void
print_rows(n)
int n;
{
int i;
printf("nNumber Employee Salary");
printf("n------ -------- ------n");
for (i = 0; i < n; i++)
printf("%-9d%-15.15s%9.2fn", emp_rec.emp_number[i],
emp_rec.emp_name[i], emp_rec.salary[i]);
}
/* 에러 출력 함수 */
void
sql_error(msg)
char *msg;
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("n%s", msg);
printf("n% .70s n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
4-5) Sample Program : Host Arrays Using Scrollable Cursor
: 아래의 예제 프로그램은 scrollable Cursor를 사용해서 호스트 배열을 어떻게 사용하는지 예제
를 보여주고 있다.
주의) 결과셋에서 행의 수를 결정하기 위해서 FETCH LAST를 하는 것을 주의 깊게 살펴보자.
/*
* 이프로그램은 hr/hr 스키마를 사용한다. 이프로그램을 실행하기전에 이 스키마가 존재
* 하는지 확인하기 바란다.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlca.h>
#define ARRAY_LENGTH 4
/* 사용자 아이디와 비밀번호 */
char *username = "hr";
char *password = "hr";
/* 호스트 구조체 선언 */
struct emp_rec_array
{
int emp_number;
char emp_name[20];
float salary;
} emp_rec[ARRAY_LENGTH];
/* 퀴리의 결과를 출력 */
void print_rows()
{
int i;
for (i=0; i<ARRAY_LENGTH; i++)
printf("%d %s %8.2fn", emp_rec[i].emp_number,
emp_rec[i].emp_name, emp_rec[i].salary);
}
/* 오라클 에러 처리 */
void sql_error(char *msg)
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("n%s", msg);
printf("n% .70s n", sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
exit(EXIT_FAILURE);
}
void main()
{
int noOfRows; /* 행수 */
/* 에러처리 */
EXEC SQL WHENEVER SQLERROR DO sql_error("Connect error:");
/* 데이터베이스 연결 */
EXEC SQL CONNECT :username IDENTIFIED BY :password;
/* 에러처리 */
EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error:");
/* scrollable mode에 커서를 선언 */
EXEC SQL DECLARE c1 SCROLL CURSOR FOR
SELECT employee_id, first_name, salary FROM employees;
EXEC SQL OPEN c1;
EXEC SQL WHENEVER SQLERROR DO sql_error("Fetch Error:");
/* 이것은 dummy fetch로서 결과셋에서 행수를 찾는다. */
EXEC SQL FETCH LAST c1 INTO :emp_rec;
/* 결과셋의 행수는 sqlca.sqlerrd[2]값으로 주어진다. */
noOfRows = sqlca. sqlerrd[2];
printf("Total number of rows in the result set %d:n", noOfRows);
/* ARRAY_LENGTH만큼의 행수를 취득한다. */
EXEC SQL FETCH FIRST c1 INTO :emp_rec;
printf("******************** DEFAULT : n");
print_rows();
/* 다음 ARRAY_LENGTH 행수를 취득한다. */
EXEC SQL FETCH NEXT c1 INTO :emp_rec;
printf("******************** NEXT : n");
print_rows();
/* 3번째 ARRAY_LENGTH 만큼 취득 */
EXEC SQL FETCH ABSOLUTE 3 c1 INTO :emp_rec;
printf("******************** ABSOLUTE 3 : n");
print_rows();
/* 현재 ARRAY_LENGTH 를 취득 */
EXEC SQL FETCH CURRENT c1 INTO :emp_rec;
printf("******************** CURRENT : n");
print_rows();
/* 현재 커서위치에서 ARRAY_LENGTH 행을 두번째 offset으로 취득 */
EXEC SQL FETCH RELATIVE 2 c1 INTO :emp_rec;
printf("******************** RELATIVE 2 : n");
print_rows();
/* 다시 첫번째 ARRAY_LENGTH 행수를 취득 */
EXEC SQL FETCH ABSOLUTE 0 c1 INTO :emp_rec;
printf("******************** ABSOLUTE 0 : n");
print_rows();
/* 커서를 닫는다. */
EXEC SQL CLOSE c1;
/* 데이터베이스 종료 */
EXEC SQL COMMIT WORK RELEASE;
exit(EXIT_SUCCESS);
}
4-6) 호스트 배열 제한사항
: SELECT문의 WHERE절에서 호스트 배열을 사용할 수는 없다. ( 단 서버쿼리 제외)
SELECT나 FTECH 절의 INTO에서 호스트배열과 호스트 변수를 혼용해서 사용할 수 없다.
5) Inserting with Arrays
: insert 문에서 입력변수로 호스트 변수를 사용할 수 있다. 배열에 요소가 부적절하다면, 입력된 행
수를 제어하기 위해서 FOR 절을 사용할 수 있다. 호스트 배열을 가지고 입력하는 예제가 아래에 있다.
char emp_name[50][20];
int emp_number[50];
float salary[50];
/* 호스트 배열을 채운다. */
...
EXEC SQL INSERT INTO EMP (ENAME, EMPNO, SAL)
VALUES (:emp_name, :emp_number, :salary);
입력된 누적행수는 sqlca.sqlerrd[2] 찾을 수 있다.
아래의 예제는 한번에 한행씩 입력되는 예제로 위의 예제보다는 효율성이 떨어지는 예제이다.
왜냐하면 각행이 입력될때마다 서버의 호출이 일어 나기 때문이다.
for (i = 0; i < array_size; i++)
EXEC SQL INSERT INTO emp (ename, empno, sal)
VALUES (:emp_name[i], :emp_number[i], :salary[i]);
5-1) 배열 Insert인 경우 제한사항
: Insert 문의 Values 절에 배열포인터를 사용할 수 없다.
Insert 문의 values 절에 호스트 배열과 호스트 변수를 혼용 할 수 없다.
6) 배열을 사용한 UPDATE
: 아래의 예제처럼 UPDATE 문에 호스트 배열을 사용 할 수 있다.
int emp_number[50];
float salary[50];
/* populate the host arrays */
EXEC SQL UPDATE emp SET sal = :salary
WHERE EMPNO = :emp_number;
Update된 축적행수는 sqlerrd[2]에서 찾을 수 있다. 이 수는 update cascade에 의해서 처리된
행을 포함하지는 않는다. 배열의 요소가 부적절하다면, update된 행의 수를 제한 하기위해서 SQL FOR 절을 사용할 수 있다.
6-1) 배열로 UPDATE 시 제한 사항
: 호스트 변수와 호스트배열을 혼용해서 SET 혹은 WHERE 절에 사용할 수 없으며, UPDATE문에 CURRENT
OF 절에 호스트 배열을 사용할 수 없다.
7) 배열을 사용한 DELETE 처리
: DELETE 문에서 입력변수로 호스트 배열을 사용할 수 있다. WHERE 절에 호스트 배열을 사용해서
반복적으로 DELETE 문을 실행 할 수 있다. 호스트 배열을 사용해서 삭제하는 예제는 아래와같다.
...
int emp_number[50];
/* populate the host array */
...
EXEC SQL DELETE FROM emp
WHERE empno = :emp_number;
삭제된 누적 행수는 sqlerrd[2]에서 얻을 수 있다.
7-1) 배열을 사용한 DELETE 처리시 제한사항
: where 절에 호스트변수와 호스트배열을 사용할 수 없다.
DELETE 문에 CURRENT OF 절에 호스트 배열을 사용할 수 없다.



출처 - http://younbok.egloos.com/9342717

:

[번역] 호스트배열 (Host Arrays) - 01

Language/Pro*C 2015. 5. 20. 17:16

목 차
▣ 왜 배열을 사용하는가?
▣ 호스트 배열의 선언
▣ SQL문에서의 배열사용
▣ 배열로 Select하기
▣ 배열과 Insert하기
▣ 배열과 Update하기
▣ 배열과 Delete하기
▣ FOR절 사용
▣ WHERE절 사용
▣ 배열 구조체
▣ Mimicking CURRENT OF
▣ sqlca.sqlerrd[2] 사용

1) 왜 배열을 사용하는가?
배열은 프로그래밍하는 시간을 줄이며, 성능 향상을 시킬수 있다. 오라클과의 통신
과부하도 줄일수 있다. 예를 들어, 300명의 사원정보를 입력해야한다고 가정할때
배열이 없다면, 각사원의 정보를 insert해야하지만 배열을 사용하여 1번의 insert
문을 사용해서 입력할 수 있다.

2) 호스트 배열의 선언
아래의 예제는 배열을 선언한 예이다.

char emp_name[50][10];
int emp_number[50];
float salary[50];

VARCHAR형의 배열도 선언이 가능하다.

VARCHAR v_array[10][30];

2-1) 제한사항
object형에대한것을 제외하고, 호스트배열의 포인터를 선언 할수는 없다.
문자형배열을 제외하고, 1차원배열만을 지원한다.
아래의 예제는 유효하지 않은 선언이다.

int hi_lo_scores[25][25]; /* not allowed */

2-2) 배열의 최대크기
배열의 최대크기는 32K정도이며 이는 시스템에 따라서, 운영체제에 따라서 달라
질 수 있다.최대크기를 넘었을경우 "parameter out of range"라는 런타임에러가
발생하게 된다.

3) SQL문에서의 배열사용
SQL문에서 배열은 입력변수,출력변수로서 사용할 수 있다.

3-1) 호스트배열 참조
아래의 예제에서 25개행이 입력된다.

int emp_number[50];
char emp_name[50][10];
int dept_number[25];

/* Populate host arrays here. */
EXEC SQL INSERT INTO emp (empno, ename, deptno)
VALUES (:emp_number, :emp_name, :dept_number);

반복문을 사용해서 아래와 같이 입력하는 것도 가능한다.

for (i = 0; i < 50; i += 5)
EXEC SQL INSERT INTO emp (empno, deptno)
VALUES (:emp_number[i], :dept_number[i]);

그러나, 입력해야할 데이터가 더 많을경우 이것에 대한 처리는 할 수가 없게된다.
오라클은 호스배열수가 n개라면 n번 실행해야할 문장으로 다룬다.

3-2) 지시자 배열의 사용
지시자배열은 입력호스트배열에 NULL을 할당하기위해서 지시자변수를 사용하며,
출력호스트배열에 NULL을 감지하거나, 값이 짤려졌는지를 확인하기위해서 사용한다.
아래의 예제는 지시자배열과 함께 INSERT하는 방법을 보여주고 있다.

int emp_number[50];
int dept_number[50];
float commission[50];
short comm_ind[50]; /* indicator array */

/* Populate the host and indicator arrays. To insert a null
into the comm column, assign -1 to the appropriate
element in the indicator array. */
EXEC SQL INSERT INTO emp (empno, deptno, comm)
VALUES (:emp_number, :dept_number,
:commission INDICATOR :comm_ind);

3-3)오라클 제한 사항
VALUES, SET, INTO, 혹은 WHERE 절에서는 호스트 배열을 사용할 수 없다.
UPDATE 혹은DELETE 문의 CURRENT OF과 함께 호스트배열은 사용할 수 없다.


출처 - http://younbok.egloos.com/9342718

'Language > Pro*C' 카테고리의 다른 글

[번역] 호스트배열 (Host Arrays) - 03  (0) 2015.05.20
[번역] 호스트배열 (Host Arrays) - 02  (0) 2015.05.20
[번역] Embedded PL/SQL - 04  (0) 2015.05.20
[번역] Embedded PL/SQL - 03  (0) 2015.05.20
[번역] Embedded PL/SQL - 02  (0) 2015.05.20
:

[번역] Embedded PL/SQL - 04

Language/Pro*C 2015. 5. 20. 17:15

목 차
▣ PL/SQL의 장점( Advantages of PL/SQL )
▣ Embedded PL/SQL Blocks
▣ 호스트 변수( Host Variables )
▣ 지시자 변수( Indicator Variables )
▣ 호스트 배열 ( Host Arrays )
▣ 임베디트 PL/SQL에서 커서 사용방법 (Cursor Usage in Embedded PL/SQL )
▣ Stored PL/SQL and Java Subprograms

▣ 외부 프로시져( External Procedures )
▣ Dynamic SQL 사용 ( Using Dynamic SQL )

8) 외부 프로시져( External Procedures )
PL/SQL에서 C함수를 사용할수 있다. C함수는 동적라이브러리 내에 저장되어 있는것으로
사용하는 방법은 아래와 같다.

EXEC SQL REGISTER CONNECT USING :epctx [RETURNING :host_context] ;

epctx는 external procedure context이다. 이것을 이용하여 OCIEnv, OCISvcCtx, OCIError등과
같은 OCI핸들을 사용할 수 있게 되는것이다.

8-1) 외부 프로시져의 제한 사항
- C++외부프로시져는 지원않한다.
- 외부프로시져 Context에 연결시 추가연결은 않된다.
- EXEC SQL ENABLE THREADS문을 사용할 수 없다.
- DDL문을 사용할 수 없다.
- EXEC SQL COMMIT / ROLLBACK문을 사용할 수 없다.
- EXEC SQL OBJECT문과같은 오브젝트문을 사용할 수 없다.
- EXEC SQL LOB문을 사용할 수 없다.
- EXEC TOOLS문을 사용할 수 없다.
8-2) 외부 프로시져 생성
생성하는 예제는 아래와 같다.
CREATE OR REPLACE PROCEDURE extp1
AS EXTERNAL NAME "extp1"
LIBRARY mylib
WITH CONTEXT
PARAMETERS(CONTEXT) ;
SQL*Plus에서는 아래와 같이 사용한다.
SQL>
BEGIN
INSERT INTO emp VALUES(9999,’JOHNSON’,’SALESMAN’,7782, sysdate, 1200,150,10);
extp1;
END;
아래의 내용은 extp1.pc파일의 리스트이다.
void extp1 (epctx)
OCIExtProcContext *epctx;
{
char name[15];
EXEC SQL REGISTER CONNECT USING :epctx;
EXEC SQL WHENEVER SQLERROR goto err;
EXEC SQL SELECT ename INTO :name FROM emp WHERE empno = 9999;
return;
err: SQLExtProcError(SQL_SINGLE_ RCTX,
sqlca.sqlerrm.sqlerrmc,sqlca.sqlerrm.sqlerrml);
return;
}
9) Dynamic SQL 사용 ( Using Dynamic SQL )
PL/SQL블록내에 호스트변수를 포함하고 있지 않다면, Dynamic SQL Method 1을
사용할 수 있고, 호스트 변수를 포함하고 있다면 Dynamic SQL Method 2를 사용
할 수 있다.



출처 - http://younbok.egloos.com/9342719

'Language > Pro*C' 카테고리의 다른 글

[번역] 호스트배열 (Host Arrays) - 02  (0) 2015.05.20
[번역] 호스트배열 (Host Arrays) - 01  (0) 2015.05.20
[번역] Embedded PL/SQL - 03  (0) 2015.05.20
[번역] Embedded PL/SQL - 02  (0) 2015.05.20
[번역] Embedded PL/SQL - 01  (0) 2015.05.20
:

[번역] Embedded PL/SQL - 03

Language/Pro*C 2015. 5. 20. 17:15

목 차
▣ PL/SQL의 장점( Advantages of PL/SQL )
▣ Embedded PL/SQL Blocks
▣ 호스트 변수( Host Variables )
▣ 지시자 변수( Indicator Variables )
▣ 호스트 배열 ( Host Arrays )
▣ 임베디트 PL/SQL에서 커서 사용방법 (Cursor Usage in Embedded PL/SQL )
▣ Stored PL/SQL and Java Subprograms
▣ 외부 프로시져( External Procedures )
▣ Dynamic SQL 사용 ( Using Dynamic SQL )

6) Embedded PL/SQL에서 커서 사용
프로그램에서 동시에 사용할 수 있는 커서의 최대수는 OPEN_CURSOR 파라미터에
의해서 초기에 결정된다. 아래의 계산은 사용된 커서의 최대수를 결정하는 방법을
보여주고 있다. 이와같은 방법으로 계산된 커서의 합계는 OPEN_CURS0RS를 초과
할 수 없다.

SQL statement cursors
PL/SQL parent cursors
PL/SQL child cursors
+ 6 cursors for overhead
--------------------------
Sum of cursors in use

연결수를 초과하면 오라클은 에러를 발생한다.

7) Stored PL/SQL and Java Subprograms
SQL*Plus와같은 오라클 툴을 사용해서 생성된 subprogram을 stored subprogram이라고
부른다. 데이터 사전에 한번 컴파일되고 저장되면 데이터베이스 오브젝트가되고,
이것은 다시 컴파일하지 않고 재 실행 할 수 있다.

PL/SQL block이나 스토어드 프로시져내의 subprogram이 오라클로 보내졌을때
이 subprogram을 inline subprogram이라고 부른다. 오라클은 inline subprogram을
컴파일하고 그것을 SGA(System Global Area)에 저장한다. 하지만 소스 자체나 오브젝트
코드를 데이터 사전에 저장 하지는 않는다.

패키지내에 정의된 subprogram을 packaged subprogram이라고 부르면 패키지에 정의되지
않은 stored subprogram은 standalone subprogram이라고 부른다.

7-1) Stored Subprogram 생성
호스트 프로그램에 CREATE FUNCTION, CREATE PROCEDURE, CREATE PACKAGE를 SQL문에
끼워 넣을 수 있다. 아래의 예제를 보자.

EXEC SQL CREATE
FUNCTION sal_ok (salary REAL, title CHAR)
RETURN BOOLEAN AS
min_sal REAL;
max_sal REAL;
BEGIN
SELECT losal, hisal INTO min_sal, max_sal
FROM sals
WHERE job = title;
RETURN (salary >= min_sal) AND
(salary <= max_sal);
END sal_ok;
END-EXEC;
위의 예제에서 주목할 것은 EXEC SQL EXECUTE가 아닌 EXEC SQL로 시작하며
END-EXEC로 끝난다.

다음에 나올 예제는 get_employees라는 프로시져를 포함한 패키지를 생성한다.
batch크기는 다른 stored subprogram이나 클라이언트 프로그램에 있는 프로시져를
호출 하면서 결정된다.

프로시져는 OUT형식의 파라미터로 PL/SQL테이블을 3개 선언한다. 그리고 사원 데이터를
취득한다. 실제 파라미터는 호스트배열이다. 프로시져가 끝났을때 자동적으로 호스트
배열에 PL/SQL테이블에 모든 행값들을 할당한다.

EXEC SQL CREATE OR REPLACE PACKAGE emp_actions AS
TYPE CharArrayTyp IS TABLE OF VARCHAR2(10)
INDEX BY BINARY_INTEGER;
TYPE NumArrayTyp IS TABLE OF FLOAT
INDEX BY BINARY_INTEGER;
PROCEDURE get_employees(
dept_number IN INTEGER,
batch_size IN INTEGER,
found IN OUT INTEGER,
done_fetch OUT INTEGER,
emp_name OUT CharArrayTyp,
job_title OUT CharArrayTyp,
salary OUT NumArrayTyp);
END emp_actions;
END-EXEC;

EXEC SQL CREATE OR REPLACE PACKAGE BODY emp_actions AS

CURSOR get_emp (dept_number IN INTEGER) IS
SELECT ename, job, sal FROM emp
WHERE deptno = dept_number;
PROCEDURE get_employees(
dept_number IN INTEGER,
batch_size IN INTEGER,
found IN OUT INTEGER,
done_fetch OUT INTEGER,
emp_name OUT CharArrayTyp,
job_title OUT CharArrayTyp,
salary OUT NumArrayTyp) IS
BEGIN
IF NOT get_emp%ISOPEN THEN
OPEN get_emp(dept_number);
END IF;
done_fetch := 0;
found := 0;
FOR i IN 1..batch_size LOOP
FETCH get_emp INTO emp_name(i),
job_title(i), salary(i);
IF get_emp%NOTFOUND THEN
CLOSE get_emp;
done_fetch := 1;
EXIT;
ELSE
found := found + 1;
END IF;
END LOOP;
END get_employees;
END emp_actions;
END-EXEC;

7-2) Stored PL/SQL 혹은 Java Subprogram 호출
호스트 프로그램에서 stored subprogram를 호출하기위해서는, anonymous PL/SQL block
을 사용하든지, CALL문을 사용 할 수 있다.

7-2-1) Anonymous PL/SQL Block
아래의 예제를 보면, raise_salary라는 standalone프로시져를 호출한다.

EXEC SQL EXECUTE
BEGIN
raise_salary(:emp_id, :increase);
END;
END-EXEC;

stored subprogram들은 파라미터를 가질 수 있다. 위의 예제에서 실제 파라미터는
emp_id와 increase이다.

EXEC SQL EXECUTE
BEGIN
emp_actions.raise_salary(:emp_id, :increase);
END;
END-EXEC;

위의 예제는 emp_actions 패키지에 저장된 프로시져를 사용하는 예제이다.

아래의 예제는 get_employees 프로시져를 반복적으로 호출하고 데이터가 없을때까지
사원데이터를 보여준다. 이예제에서 3개의 형식적인 파라미터는 PL/SQL테이블이며
이에 상응하는 실제 파라미터는 호스트 배열이다.

/******************************************************************************
/*
/* Sample Program 9: stored procedure 호출
/* SCOTT/TIGER 계정으로 오라클에 연결하고 여러개의 호스트 배열
/* 을 선언하고, CALLDEMO package에 선언한 GET_EMPLOYEES을 사용하여
/* ASIZE값까지 값을 취득한다.
/*
*******************************************************************************/

#include <stdio.h>
#include <string.h>
EXEC SQL INCLUDE sqlca.h;
typedef char asciz[20];
typedef char vc2_arr[11];
EXEC SQL BEGIN DECLARE SECTION;
/* 사용자 정의 문자열 */
EXEC SQL TYPE asciz IS STRING(20) REFERENCE;
/* 사용자정의 VARCHAR 배열요소 */
EXEC SQL TYPE vc2_arr IS VARCHAR2(11) REFERENCE;

asciz username;
asciz password;
int dept_no; /* 쿼리를 위한 부서 */
vc2_arr emp_name[10]; /* 리턴받는 이름 배열 */
vc2_arr job[10];
float salary[10];
int done_flag;
int array_size;
int num_ret; /* 리턴되는 행수 */
EXEC SQL END DECLARE SECTION;
long SQLCODE;
void print_rows(); /* 프로그램 출력처리 함수 */
void sql_error(); /* 에러처리 함수 */

///////////////////////////////////////////////////////////////////////////////
// 메인함수
///////////////////////////////////////////////////////////////////////////////
void 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: %snn", username);
printf("Enter department number: ");
gets(temp_buf);
dept_no = atoi(temp_buf);/* Print column headers. */
printf("nn");
printf("%-10.10s%-10.10s%sn", "Employee", "Job", "Salary");
printf("%-10.10s%-10.10s%sn", "--------", "---", "------");
/* 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(n)
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.2fn",
emp_name[i], job[i], salary[i]);
}

///////////////////////////////////////////////////////////////////////////////
// 에러처리함수
///////////////////////////////////////////////////////////////////////////////
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);
}
7-2-2) 원격 접근
원격접근해서 아래와 같이 PL/SQL을 사용할 수 있다.
dallas라고 하는 원격에 있는 데이터 베이스의 raise_salary프로시져를 호출해서
사용하는 예제를 보여주고 있다.

EXEC SQL EXECUTE
BEGIN
raise_salary@dallas(:emp_id, :increase);
END;
END-EXEC;

아래와 같이 synonym을 사용해서 위치 투명성을 제공할 수도 있다.

CREATE PUBLIC SYNONYM raise_salary
FOR raise_salary@dallas;
7-2-3) CALL문
CALL문은 아래와같은 형태를 가진다.
EXEC SQL
CALL [schema.] [package.]stored_proc[@db_link](arg1, ...)
[INTO :ret_var [[INDICATOR]:ret_ind]] ;

schema : 프로시져가 포함하고 있는 스키마
package : 프로시져가 포함된 패키지
stored_proc : Java 혹은 PL/SQL stored procedure
db_link : remote database link
arg1... : 넘겨지는 파라미터
ret_var : 결과를 추출하는 선택적인 호스트 변수
ind_var : ret_var을 위한 선택적인 지시자 변수

7-2-4) CALL문 예제
정수로 인자를 넘겨받고 팩토리얼로 리턴받는 fact함수를 생성하는 예제이다.

EXEC SQL CREATE OR REPLACE PACKAGE BODY mathpkg as
function fact(n IN INTEGER) RETURN INTEGER AS
BEGIN
IF (n <= 0) then return 1;
ELSE return n * fact(n - 1);
END IF;
END fact;
END mathpkge;
END-EXEC.

Pro*C/C++에서 CALL문을 사용해서 fact함수를 사용하는 예는 다음과 같다.
...

int num, fact;
...

EXEC SQL CALL mathpkge.fact(:num) INTO :fact ;
...



출처 - http://younbok.egloos.com/9342720

'Language > Pro*C' 카테고리의 다른 글

[번역] 호스트배열 (Host Arrays) - 01  (0) 2015.05.20
[번역] Embedded PL/SQL - 04  (0) 2015.05.20
[번역] Embedded PL/SQL - 02  (0) 2015.05.20
[번역] Embedded PL/SQL - 01  (0) 2015.05.20
[번역] Embedded SQL - 03  (0) 2015.05.20
:

[번역] Embedded PL/SQL - 02

Language/Pro*C 2015. 5. 20. 17:14

목 차
▣ PL/SQL의 장점( Advantages of PL/SQL )
▣ Embedded PL/SQL Blocks
▣ 호스트 변수( Host Variables )
▣ 지시자 변수( Indicator Variables )
▣ 호스트 배열 ( Host Arrays )
▣ 임베디트 PL/SQL에서 커서 사용방법 (Cursor Usage in Embedded PL/SQL )
▣ Stored PL/SQL and Java Subprograms
▣ 외부 프로시져( External Procedures )
▣ Dynamic SQL 사용 ( Using Dynamic SQL )

5) 호스트 배열 ( Host Arrays )
PL/SQL블록에서 입력호스트배열과 지시자 배열을 넘길 수 있다.

아래의 예제에서, 함수 호출시에 배열을 사용하는 salary라고 이름 붙여진
배열을 넘긴다. 이 함수는 값들중에서 중간값을 취득하기위해서 mdidan이라고
이름붙여졌으며, 이 함수의 형식적인 파라미터는 num_tab이라고 이름 붙여진
PL/SQL테이블을 포함하고 있다. 그 호출 함수는 실제 파라미터 salary에
모든값을 형식적인 파라미터 num_tab의 행에 할당한다.

...

float salary[100];

/* populate the host array */

EXEC SQL EXECUTE
DECLARE
TYPE NumTabTyp IS TABLE OF REAL
INDEX BY BINARY_INTEGER;
median_salary REAL;
n BINARY_INTEGER;
...

FUNCTION median (num_tab NumTabTyp, n INTEGER)
RETURN REAL IS
BEGIN
-- compute median
END;
BEGIN
n := 100;
median_salary := median(:salary, n);
...

END;
END-EXEC;
...

테이블 7-1은 PL/SQL테이블에서 행을 값들과 호스트 배열의 요소들 사이에
가능한 변환을 보여주고 있다. 예를들어, LONG형의 호스트 배열은
VARCHAR2, LONG, RAW, 혹은 LONG RAW형의 PL/SQL 테이블과 호환되며,
CHAR형과는 호환되지 않는다.






5-1) ARRAYLEN문
입력호스트 변수를 PL/SQL block에 넘겨야만 한다고 가정해보자. 기본적으로,
호스트 배열을 사용할때, Proc*C/C++ 전처리기는 선언된 수치를 사용한다.
하지만 선언된 수치를 전부 사용할 필요가 없을경우, ARRAYLEN문을 사용해서 작은
배열 수치를 적용할 수 있다.
적용하는 문법은 다음과 같다 :

EXEC SQL ARRAYLEN host_array (dimension) [EXECUTE];
4바이트 정수 호스트 변수 (문자는 않됨)

아래의 예제는 bonus라고 이름붙여진 C 호스트배열의 기본 수치를 그대로 사용하기
위해서 ARRAYLEN문을 사용한 예제이다.

float bonus[100];
int dimension;

EXEC SQL ARRAYLEN bonus (dimension);

/* populate the host array */
...

dimension = 25; /* set smaller array dimension */
EXEC SQL EXECUTE
DECLARE
TYPE NumTabTyp IS TABLE OF REAL
INDEX BY BINARY_INTEGER;
median_bonus REAL;

FUNCTION median (num_tab NumTabTyp, n INTEGER)
RETURN REAL IS
BEGIN
-- compute median
END;

BEGIN
median_bonus := median(:bonus, :dimension);
...
END;
END-EXEC;

위의 예제에서 PL/SQL블록에 25 배열요소가 전달되었으며 결과적으로,PL/SQL블록에
오라클 실행을 위해서 보내졌을경우 더욱 적은 호스트 배열이 보내진것이며, 이것은
시간을 절약할 수 있고, 네트웍 부하또한 줄일 수 있다.



출처 - http://younbok.egloos.com/9342721

'Language > Pro*C' 카테고리의 다른 글

[번역] Embedded PL/SQL - 04  (0) 2015.05.20
[번역] Embedded PL/SQL - 03  (0) 2015.05.20
[번역] Embedded PL/SQL - 01  (0) 2015.05.20
[번역] Embedded SQL - 03  (0) 2015.05.20
[번역] Embadded SQL - 02  (0) 2015.05.20
:

[번역] Embedded PL/SQL - 01

Language/Pro*C 2015. 5. 20. 17:13
목 차
▣ PL/SQL의 장점( Advantages of PL/SQL )
▣ Embedded PL/SQL Blocks
▣ 호스트 변수( Host Variables )
▣ 지시자 변수( Indicator Variables )
▣ 호스트 배열 ( Host Arrays )
▣ 임베디트 PL/SQL에서 커서 사용방법 (Cursor Usage in Embedded PL/SQL )
▣ Stored PL/SQL and Java Subprograms
▣ 외부 프로시져( External Procedures )
▣ Dynamic SQL 사용 ( Using Dynamic SQL )
1) PL/SQL의 장점( Advantages of PL/SQL )
이장은 PL/SQL이 제공하는 장점및 특징에 대해서 설명한다.
☞ 더 나은 성능
☞ 오라클 통합(Integration with Oracle)
☞ FOR 반복문을위한 커서(Cursor FOR Loops )
☞ 프로시져와 함수
☞ 패키지(Packages)
☞ PL/SQL테이블
☞ 사용자정의 레코드 ( User_Defined Records )

1-1) 더 나은 성능 ( Better Performance )
PL/SQL은 과부하를 줄이고, 성능을 향상시키며 생상성을 증대한다. 예를들어,
PL/SQL이 없으면 오라클은 한번에 한개의 SQL문을 처리해야만한다. PL/SQL은 서버에
SQL문 블록을 보낼 수 있다. 이것은 프로그램과 오라클간의 통신을 최소화한다.

1-2) Integration with Oracle
대부분의 오라클 데이터유형은 오라클 데이터사전에 내재된 것이다. 더욱이,
%TYPE 속성은 아래의 예처럼 사용할 수 있다.

job_title emp.job%TYPE;

위의 예처럼, 컬럼의 데이터 유형을 정확히 알 필요가 없다. 컬럼의 정의가 바뀐다고
하더라도 자동적으로 형이 변경된것으로 적용된다. 이것은 데이타에 의존적이지 않고
유지보수 비용을 줄일 수 있다.

1-3) Cursor FOR Loops
커서를 조작하고 선언하기위해서, PL/SQL에서는 DECLARE, OPEN, FETCH, CLOSE문을
사용할 필요가 없다. 대신 cursor FOR Loop문을 사용할 수 있다.
아래에 예가 있다.

DECLARE
...

BEGIN
FOR emprec IN (SELECT empno, sal, comm FROM emp) LOOP
IF emprec.comm / emprec.sal > 0.25 THEN ...
...

END LOOP;
END;

1-4) 프로시져와 함수
PL/SQL은 프로시져와 함수라고하는 두가지 서브프로그램 유형을 가지고 있다.
행위를 수행하기위해서 프로시져를 사용하고 값을 산정하기위해서 함수를 사용한다.
신규부서를 생성하는 프로시져가 필요하다면 아래의 예제와같이 하면된다.

PROCEDURE create_dept
(new_dname IN CHAR(14),
new_loc IN CHAR(13),
new_deptno OUT NUMBER(2)) IS
BEGIN
SELECT deptno_seq.NEXTVAL INTO new_deptno FROM dual;
INSERT INTO dept VALUES (new_deptno, new_dname, new_loc);
END create_dept;

인자에는 3가지 모드가 있다 : IN(default), OUT, IN OUT.
IN - 서브프로그램이 호출될때 값을 넘겨주는 파라미터
OUT - 호출자에게 값을 리턴해줄때 사용하는 파라미터
IN OUT - 초기에는 서버프로그램에 인자를 넘기며, 호출자에게 변경된값을 리턴한다.

1-5) 패키지 ( Package )
PL/SQL은 논리적인 관계유형, 프로그램 오브젝트, 서브프로그램을 패키지로 묶을
수 있도록한다. 아래의 예제에서처럼 패키지는 분류(Specification)와 몸체(Body)로
분를할수 있으며, 분류(specification)는 유형,상수,변수,예외,커서, 이용할수
있는 서브 프로그램과같은 프로그램의 인터페이스를 말한다.
몸체(body)는 커서및 서브프로그램을 정의하고, 분류를 구현한 부분이다.

PACKAGE emp_actions IS -- package specification
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...);
PROCEDURE fire_employee (emp_id NUMBER);
END emp_actions;

PACKAGE BODY emp_actions IS -- package body
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...) IS
BEGIN
INSERT INTO emp VALUES (empno, ename, ...);
END hire_employee;
PROCEDURE fire_employee (emp_id NUMBER) IS
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END fire_employee;
END emp_actions;

패키지의 분류(specification)에서 선언부분만 보여지고 프로그램이 접근할 수 있으며
구현부분은 숨겨지고 접근할 수 없게 된다.

1-6) PL/SQL 테이블들
PL/SQL은 TABLE이라고 이름 붙여진 혼합 데이타 유형을 제공한다.
아래의 예제에서 NumTabTyp라고하는 테이블 유형 선언을 볼 수 있다.

...

DECLARE
TYPE NumTabTyp IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
...

BEGIN
...

END;
...

1-7) 사용자정의 레코드( User-Defined Records )
아래의 예제처럼 사용자 정의 레코드를 사용하여 PL/SQL에 적용 할 수 있다.

DECLARE
TYPE DeptRecTyp IS RECORD
(deptno NUMBER(4) NOT NULL, -- default is NULL allowed
dname CHAR(9),
loc CHAR(14));

사용방법은 아래와 같이 선언하고 사용할 수 있다.

dept_rec DeptRecTyp;

dept_rec.dname ...

2) Embedded PL/SQL Blocks
Pro*C/C++전처리기는 하나의 SQL문처럼 PL/SQL 블록을 다룬다.
SQL문이 위치 할 수 있는 곳은 어디든지 PL/SQL 블록이 위치할 수 있으며, 아래의
예제처럼 ,EXEC SQL EXECUTE 와 END-EXEC 키워드로 감싸서 사용하면 된다.

EXEC SQL EXECUTE
DECLARE
...

BEGIN
...

END;
END-EXEC; // END-EXEC다음에는 세미콜론이 와야만 한다.
3) 호스트 변수 (Host Variables )
호스트변수는 호스트언어와 PL/SQL블록사이의 통신을 위한 키이다. 사용방법은
SQL문에서 사용하는 방법과 같이 사용하면되고, PL/SQL전체 블록에서 글로벌로
다루어진다.

3-1) Example: PL/SQL에서 호스트변수를 사용하는 예제
아래의 예제는 호스트 변수를 PL/SQL에서 어떻게 사용하는지를 보여주고 있다.
사번을 입력받고, 일목록, 고용일자, 봉급등을 표시하는 프로그램이다.

char username[100], password[20];
char job_title[20], hire_date[9], temp[32];
int emp_number;
float salary;

#include <sqlca.h>
printf("Username? n");

gets(username);
printf("Password? n");
gets(password);
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("Connected to Oraclen");

for (;;)
{
printf("Employee Number (0 to end)? ");
gets(temp);
emp_number = atoi(temp);
if (emp_number == 0)
{
EXEC SQL COMMIT WORK RELEASE;
printf("Exiting programn");
break;
}
/*-------------- begin PL/SQL block -----------------*/
EXEC SQL EXECUTE
BEGIN
SELECT job, hiredate, sal
INTO :job_title, :hire_date, :salary
FROM emp
WHERE empno = :emp_number;
END;
END-EXEC;
/*-------------- end PL/SQL block -----------------*/
printf("Number Job Title Hire Date Salaryn");
printf("------------------------------------n");
printf("%6d %8.8s %9.9s %6.2fn",
emp_number, job_title, hire_date, salary);
}
...
exit(0);
sql_error:
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("Processing errorn");
exit(1);

위의 예제에서는 블록내로 들어가기전에 emp_number가 설정되고 블록내에서
호스트 변수인 job_title,hire_date, salary가 설정되는것을 주목하라.

3-2) 완전한 예제
아래의 예제는 은행 이용자 번호를 입력하고, 트랜젝션 유형, 트랜젝션량,
빗혹은 사용자의 신용을 보여주고, 사용자가 존재하지 않으면, 예외를 발생한다.
트랜젝션이 완료하면 상태를 표시한다.

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

char username[20];
char password[20];
char status[80];
char temp[32];
int acct_num;
double trans_amt;
void sql_error();

void main()
{
char trans_type;
strcpy(password, "TIGER");
strcpy(username, "SCOTT");
EXEC SQL WHENEVER SQLERROR DO sql_error();
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("Connected to Oraclen");
for (;;)
{
printf("Account Number (0 to end)? ");
gets(temp);
acct_num = atoi(temp);
if(acct_num == 0)
{
EXEC SQL COMMIT WORK RELEASE;
printf("Exiting programn");
break;
}
printf("Transaction Type - D)ebit or C)redit? ");
gets(temp);
trans_type = temp[0];
printf("Transaction Amount? ");
gets(temp);
trans_amt = atof(temp);
/*----------------- begin PL/SQL block -------------------*/
EXEC SQL EXECUTE
DECLARE
old_bal NUMBER(9,2);
err_msg CHAR(70);
nonexistent EXCEPTION;
BEGIN
:trans_type := UPPER(:trans_type);

IF :trans_type = ’C’ THEN -- credit the account
UPDATE accts SET bal = bal + :trans_amt
WHERE acctid = :acct_num;

IF SQL%ROWCOUNT = 0 THEN -- no rows affected
RAISE nonexistent;
ELSE
:status := ’Credit applied’;
END IF;
ELSIF :trans_type = ’D’ THEN -- debit the account
SELECT bal INTO old_bal FROM accts
WHERE acctid = :acct_num;

IF old_bal >= :trans_amt THEN -- enough funds
UPDATE accts SET bal = bal - :trans_amt
WHERE acctid = :acct_num;
:status := ’Debit applied’;
ELSE
:status := ’Insufficient funds’;
END IF;
ELSE
:status := ’Invalid type: ’ || :trans_type;
END IF;

COMMIT;

EXCEPTION
WHEN NO_DATA_FOUND OR nonexistent THEN
:status := ’Nonexistent account’;
WHEN OTHERS THEN
err_msg := SUBSTR(SQLERRM, 1, 70);
:status := ’Error: ’ || err_msg;
END;
END-EXEC;
/*----------------- end PL/SQL block ----------------------- */
printf("nStatus: %sn", status);
}
exit(0);
}

void sql_error()
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("Processing errorn");
exit(1);
}

3-4) VARCHAR 유형
VARCHAR형은 가변적인 스트링을 선언할때 사용한다.
VARCHAR형이 입력 호스트 변수라면 크기를 설정해야만 하며, 출력 호스트 변수로
사용하려고 하면 오라클은 자동으로 길이를 설정한다. PL/SQL 블록에서 사용하기
위해서는 블록안으로 들어가기전에 초기화를 시켜주어야한다.
아래의 예제에서 이에대한 내용을 보여주고 있다.

int emp_number;
varchar emp_name[10];
float salary;
...

emp_name.len = 10; /* 길이 component를 초기화 */

EXEC SQL EXECUTE
BEGIN
SELECT ename, sal INTO :emp_name, :salary
FROM emp
WHERE empno = :emp_number;
...

END;
END-EXEC;
...

3-5) 제한사항
PL/SQL블록에서 포인터나 배열문법을 사용하지말라. PL/SQL 컴파일러는 C호스트
변수 표현을 이해하지 못하며, 그들을 파싱할 수 없다. 아래의 예제는 틀린 표현
이다.

EXEC SQL EXECUTE
BEGIN
:x[5].name := ’SCOTT’;
...

END;
END-EXEC;

이러한 에러를 피하기위해서는 아래의 코드로 수정하면된다.

name = x[5].name ;
EXEC SQL EXECUTE
BEGIN
:name := ...;
...

END;
END-EXEC;

4) 지시자 변수( Indicator Variables )
PL/SQL은 지시자 변수가 필요하지 않다. 왜냐하면, NULL인지를 확인하기위해서
IS NULL 연산자를 사용할 수가 있다.

IF variable IS NULL THEN .....

그리고, NULL을 할당하기위해서 할당 연산자를 사용할 수 있다. 예는 아래와같다.

variable := NULL;

아래의 예제는 지시자 변수를 사용하는 예제이다.

EXEC SQL EXECUTE
BEGIN
SELECT ename, comm
INTO :emp_name, :commission :ind_comm
FROM emp
WHERE empno = :emp_number;

IF :commission :ind_comm IS NULL THEN ...
...

END;
END-EXEC;

4-1) NULL값 핸들링( NULLs Handling )
block내로 들어갈때, 지시자 변수는 -1값을 가진다. PL/SQL은 자동으로
호스트 변수에 NULL을 할당한다. 블록을 빠져나올때, 만약에 호스트 변수가 NULL
이면, PL/SQL은 자동적으로 -1값으로 지시자 변수를 할당한다.
다음 예제에서 ind_sal이 블록내로 들어가기 전에 -1값으로 설정되었다면,
salary_missing 예외가 발생한다.

...

EXEC SQL EXECUTE
BEGIN
IF :salary :ind_sal IS NULL THEN
RAISE salary_missing;
END IF;
...

END;
END-EXEC;
...

4-2) 잘려진 값
PL/SQL은 문자열이 잘려서 호스트 변수에 설정될때 예외를 발생하지 않는다.
그러나 지시자 변수를 사용하면, PL/SQL은 스트링의 원래 길에서 그 값을 설정한다.
아래의 예제는, emp_name에 잘려진 값을 설정되면 ind_name의 값을 체크함으로서
알 수가 있게 된다.

...

EXEC SQL EXECUTE
DECLARE
...

new_name CHAR(10);
BEGIN
...

:emp_name:ind_name := new_name;
...

END;
END-EXEC;



출처 - http://younbok.egloos.com/9342722

'Language > Pro*C' 카테고리의 다른 글

[번역] Embedded PL/SQL - 03  (0) 2015.05.20
[번역] Embedded PL/SQL - 02  (0) 2015.05.20
[번역] Embedded SQL - 03  (0) 2015.05.20
[번역] Embadded SQL - 02  (0) 2015.05.20
[번역] Embedded SQL - 01  (0) 2015.05.20
:

[번역] Embedded SQL - 03

Language/Pro*C 2015. 5. 20. 17:11

목 차
▣ 호스트 변수 ( Host Variables )
▣ 지시자 변수 ( Indicator Variables )
▣ 기본 SQL 문장 ( The Basic SQL Statements )
▣ The DML Returning Clause
▣ 커서 ( Cursors )
▣ 최적화 힌트 ( Optimizer Hints )
▣ CURRENT OF절 ( The CURRENT OF Clause )
▣ 커서문 ( The Cursor Statements )
▣ Non-Scrollable 커서를 사용하는 예제
▣ Scrollable 커서를 사용하는 예제

6) Scrollable Cursors
Scrollable Cursor는 오라클이 SQL문장을 실행하는 곳이며, 실행되는 동안 진행되는
정보를 저장하는 작업영역이다.

커서가 실행될때, 쿼리의 결과는 결과셋(result set)이라고 불리는 행들의 셋에 위치한다.
결과셋을 순차적으로 혹은 비순차적으로 결과를 취득할 수 있다. 비순서적인 결과셋을
Scrollable Cursors라고 부른다.

Scrollable Cursor는 사용자가 결과셋을 행을 앞으로,뒤로, 무작위적 방법으로 접근
할 수 있도록 돕는다.

6-1) Scrollable Cursors의 사용
아래의 문장들은 Scrollable Cursor를 조작하거나 선언하는것을 다룬다.

DECLARE SCROLL CURSOR : DECLARE <cursor name> SCROLL CURSOR문은 쿼리와 관련된
Scrollable Cursor를 명명하는데 사용한다.

OPEN : OPEN문은 일반 커서선언과 같은 방법으로 사용한다.

FETCH : FETCH문은 무작위적 방법으로 요구되는 행을 취득하는데 사용한다.
프로그램은 위아래 혹은 처음과 끝 혹은 무작위로 한행을 취득한다.

아래의 옵션은 FETCH문에 사용할 수 있는 옵션이다.

1. FETCH FIRST 결과셋으로부터 첫번째 행을 취득한다.
2. FETCH PRIOR 현재행으로부터 이전행을 취득한다.
3. FETCH NEXT 현재위치에서 다음행를 취득한다. 이것은 일반 FETCH와 같다.
4. FETCH LAST 결과셋으로부터 마지막 행을 취득한다.
5. FETCH CURRENT 현재행을 취득한다.
6. FETCH RELATIVE n 현재행으로부터 n번째 행을 취득한다. n은 OFFSET이다.
7. FETCH ABSOLUTE n 결과셋의 시작점으로부터 n OFFSET인 n번째행을 취득한다.
아래의 예제는 결과셋으로부터 마지막 레코드를 취득하는 예제이다.

EXEC SQL DECLARE emp_cursor SCROLL CURSOR FOR
SELECT ename, sal FROM emp WHERE deptno=20;
...

EXEC SQL OPEN emp_cursor;
EXEC SQL FETCH LAST emp_cursor INTO :emp_name, :sal;
EXEC SQL CLOSE emp_cursor;

CLOSE : CLOSE문은 일반 커서의 경우와 같은 방법으로 사용하면 된다.

6-2) CLOSE_ON_COMMIT 전처리기 옵션
CLOSE_ON_COMMIT 전처리기 옵션은 COMMIT이 실행될때 모든 커서를 닫을것인지 아닌지를
선택할 수 있는 능력을 제공하는 옵션이다. 만약 MODE = ANSI일때, CLOSE_ON_COMMIT이
기본적으로 YES를 갖는다. 명시적으로 CLOSE_ON_COMMIT=NO으로 설정하면 성능이 향상된다.
왜냐하면, 커서들은 COMMIT이 실행될때 닫히지 않을것이기 때문이다.

6-3) PREFETCH 전처리기 옵션
전처리기의 PREFETCH옵션은 주어진 행수를 미리가지고옮으로해서 더욱 효율적인 쿼리가
되도록한다. 이것은 서버접속수나 전체적인 메모리 사용을 줄일수 있다. PREFETCH옵션값
의 행수는 명시적인 커서를 포함한 모든 쿼리에서 사용한다.

인라인에서 사용될때, PREFETCH옵션은 이런한 커서문장보다 선행되어야 한다.

☞ EXEC SQL OPEN cursor
☞ EXEC SQL OPEN cursor USING host_var_list
☞ EXEC SQL OPEN cursor USING DESCRIPTOR desc_name

PREFTECH값은 0에서 65535로 설정할 수 있다. 기본값은 1이다.
7) Optimizer Hints
Pro*C/C++ 전처리기는 SQL문자에서 최적화 힌트(Optimizer hints)를 지원한다.
힌트는 다음을 위해서 사용할 수 있다.
☞ Optimization approach for a SQL statement
☞ 참조테이블을 위한 접근 경로지정 (Access path for each referenced table)
☞ 조인순서(Join order for a join)
☞ 조인방법적용(Method used to join tables)

힌트는 rule-based 최적화와 cost-based 최적화를 선택하게 한다.
아래의 예제는 작업처리를 최적화하기위한 힌트를 사용한 예제이다.

EXEC SQL SELECT /*+ ALL_ROWS (cost-based) */ empno, ename, sal, job
INTO :emp_rec FROM emp
WHERE deptno = :dept_number;

cost-based optimizer와 optimizer hints에대한 더 많은 정보를 얻기위해서는
Oracle9i Application Developer’s Guide - Fundamentals장을 참조한다.
8) CURRENT OF 절
주어지 커서로부터 취득한 테이타의 최근행을 참조해서 DELETE나 UPDATE문을 사용
할 경우 CURRENT OF 커서명 절을 사용할 수 있다.
아래에 사용예제를 보여주고 있다.

EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ename, sal FROM emp WHERE job = ’CLERK’
FOR UPDATE OF sal;
...

EXEC SQL OPEN emp_cursor;
EXEC SQL WHENEVER NOT FOUND GOTO ...
for (;;) {
EXEC SQL FETCH emp_cursor INTO :emp_name, :salary;
...

EXEC SQL UPDATE emp SET sal = :new_salary
WHERE CURRENT OF emp_cursor;
}

8-1) 제한사항
CURRENT OF은 인덱스가 구성된 테이블(index-organized table)에서는 사용할 수 없다.
CURRENT OF은 호스트 배열과 함께사용할 수 없다.
CURRENT OF과 함께 테이블을 조인해서 사용 할 수 없다.
결론적으로, CURRENT OF은 Dynamic SQL과 함께 사용할 수 없다는것이다.

9) 커서문(Cursor Statements)
아래의 예제는 프로그램에서 커서제어문의 전형적인 절차를 보여주고 있다.

...

/* 커서 선언 */
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ename, job
FROM emp
WHERE empno = :emp_number
FOR UPDATE OF job;

/* 커서를 열고 active set을 확인 */
EXEC SQL OPEN emp_cursor;

/* 마지막행을 취득했다면 break */
EXEC SQL WHENEVER NOT FOUND DO break;

/* 반복문에서 데이터 취득 / 처리 */
for (;;)
{
EXEC SQL FETCH emp_cursor INTO :emp_name, :job_title;

EXEC SQL UPDATE emp
SET job = :new_job_title
WHERE CURRENT OF emp_cursor;
}
...

/* 커서를 닫음 */
EXEC SQL CLOSE emp_cursor;
EXEC SQL COMMIT WORK RELEASE;
...

10) Non-Scrollable Cursor를 사용한 예제
아래의 완전한 프로그램은 커서사용법과 FETCH문의 사용법을 보여주고 있다.
부서번호를 입력받고 부서의 모든 사원의 이름을 표시하는 프로그램이다.
FETCH한후의 에러처리부분에 대한 내용을 담고 있다.
FETCH가 실패하면 오라클에러코드는 sqlca.sqlcode에 "no data found"가 리턴된다.

#include <stdio.h>

/* 호스트변수 선언 */
char userid[12] = "SCOTT/TIGER";
char emp_name[10];
int emp_number;
int dept_number;
char temp[32];
void sql_error();

/* SQL Communications Area 포함*/
#include <sqlca.h>

////////////////////////////////////////////////////////////////////////////
// Main 함수
////////////////////////////////////////////////////////////////////////////
void main()
{
emp_number = 7499;
/* 에러처리 */
EXEC SQL WHENEVER SQLERROR do sql_error("Oracle error");

/* 오라클 연결 */
EXEC SQL CONNECT :userid;
printf("Connected.n");

/* 커서 선언 */
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ename
FROM emp
WHERE deptno = :dept_number;

printf("Department number? ");

gets(temp);

dept_number = atoi(temp);

/* 커서오픈 및 active set 확인 */
EXEC SQL OPEN emp_cursor;
printf("Employee Namen");
printf("-------------n");
/* 데이터가 없을때까지 데이터 취득 및 처리 */
EXEC SQL WHENEVER NOT FOUND DO break;
while (1)
{
EXEC SQL FETCH emp_cursor INTO :emp_name;
printf("%sn", emp_name);
}
EXEC SQL CLOSE emp_cursor;
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}

////////////////////////////////////////////////////////////////////////////
// 에러처리 함수
////////////////////////////////////////////////////////////////////////////
void sql_error(msg)
char *msg;
{
char buf[500];
int buflen, msglen;
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
buflen = sizeof (buf);
sqlglm(buf, &buflen, &msglen);
printf("%sn", msg);
printf("%*.sn", msglen, buf);
exit(1);
}

11) Scrollable Cursor를 사용한 완전한 예제
아래의 프로그램은 Scrollable Cursor사용법을 보여주고 있으며, FETCH문을 사용한
다양한 옵션을 사용하는 방법을 보여주고 있다.

#include <stdio.h>
/* 호스트변수 선언 */
char userid[12]="SCOTT/TIGER";
char emp_name[10];
void sql_error();
/* SQL Communications Area 포함*/
#include<sqlca.h>

/////////////////////////////////////////////////////////////////////////////
// 메인 함수
/////////////////////////////////////////////////////////////////////////////
void main()
{
/* 에러 처리 */
EXEC SQL WHENEVER SQLERROR do sql_error("Oracle error");
/* 오라클 연결 */
EXEC SQL CONNECT :userid;
printf("Connected.n");
/* scrollable cursor 선언 */
EXEC SQL DECLARE emp_cursor SCROLL CURSOR FOR
SELECT ename FROM emp;
/* 커서오픈 및 active set 확인 */
EXEC SQL OPEN emp_cursor;
/* 마지막행 취득 */
EXEC SQL FETCH LAST emp_cursor INTO :emp_name;
/* 5 행을 취득 */
EXEC SQL FETCH ABSOLUTE 5 emp_cursor INTO :emp_name;
/* 10 행의 데이터 취득*/
EXEC SQL FETCH RELATIVE 5 emp_cursor INTO :emp_name;
/* 7번행 취득 */
EXEC SQl FETCH RELATIVE -3 emp_cursor INTO :emp_name;
/* 첫번째 행 취득 */
EXEC SQL FETCH FIRST emp_cursor INTO :emp_name;

/* 2번행 취득 */
EXEC SQL FETCH my_cursor INTO :emp_name;
/* 3번행 취득 */
EXEC SQL FETCH NEXT my_cursor INTO :emp_name;
/* 3번행 취득*/
EXEC SQL FETCH CURRENT my_cursor INTO :emp_name;
/* 2번행 취득 */
EXEC SQL FETCH PRIOR my_cursor INTO :emp_name;
}

/////////////////////////////////////////////////////////////////////////////
// 에러처리 함수
/////////////////////////////////////////////////////////////////////////////
void sql_error(msg)
char *msg;
{
char buf[500];
int buflen , msglen;
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK TRANSACTION;
buflen = sizeof (buf);
sqlglm(buf, &buflen, &mesglen);
printf("%sn",msg);
printf("%*.sn",msglen,buf);
exit(1);
}

11-1) Positioned Update
ROWID를 사용한 Update의 예제를 보여주고 있다.
자세한 사용법은 "Universal ROWIDs"를 참조한다.

#include <oci.h>
...

OCIRowid *urowid;
...

EXEC SQL ALLOCATE :urowid;
EXEC SQL DECLARE cur CURSOR FOR
SELECT rowid, ... FROM my_table FOR UPDATE OF ...;
EXEC SQL OPEN cur;
EXEC SQL FETCH cur INTO :urowid, ...;

/* Process data */
...

EXEC SQL UPDATE my_table SET ... WHERE CURRENT OF cur;
EXEC SQL CLOSE cur;
EXEC SQL FREE :urowid;

...



출처 - http://younbok.egloos.com/9342723

: