CATEGORY

분류 전체보기 (73)
세상사는이야기 (27)
회사이야기 (7)
친구들이야기 (6)
공부이야기 (33)
프로그래밍 (3)
Network (23)
개인적인이야기 (0)

RECENT ARTICLE

RECENT COMMENT

ARCHIVE

LINK



  1. 2008.04.02
    fork 란?
  2. 2008.04.01
    버클리 데이터베이스란?
  3. 2008.04.01
    ProC
fork 함수는 원래 실행되던 프로세스의 복사본을 만드는 함수이다.

최초의 프로세스를 부모 프로세스라고 하고 fork 되어서 만들어진 프로세스를 자식 프로세스라고 한다. 자식프로세스는 fork 를 실행한 부모프로세스의 기존 태스크구조를 그대로 가져온다. 그리고 두 개의 프로세스는 동시에 실행된다. 하지만 fork로 새로 만들어진 자식 프로세스는 자신만의 process id를 가지게 된다.

다시 말해 fork 는 새로운 프로세스를 위한 메모리를 할당한후, fork 를 호출한 프로세스를 새로운 공간으로 전부 복사한다. 그리고 나서 원래 프로세스는 원래 프로세스대로 실행되고, fork 를 이용해서 생성된 프로세스도 그 나름대로 fork 시스템 콜이 수행된 라인의 다음 라인부터 실행이 된다는 것이다.

어떤 시스템이 기본적인 프로세스를 실행한 상태에서 대기중일때 어떤 요구가 들어오면 자식 프로세스를 하나 생성시킨후 요구에 대응한 일을 처리해준다. 그리고 요구된 사항이 종료되면 프로세스를 종료하고 다시 대기하게 되는것이다.

fork 함수는 멀티프로세싱을 위한 기본적인 함수라는 것을 알 수 있다.

fork 가 성공한다면 부모 프로세스에게는 자식의 process id를 반환하며, 자식 프로세스에게는 0을 반환한다.

만약 실패한다면 부모 프로세스에게 -1을 반환하며, 자식 프로세스는 생성되지 않는다.
And
 
 
 
 
 

버클리 데이터베이스는 트랜잭션을 관리해 주는 소스가 개방된 라이브러리형 데이터베이스로서 확장성과 성능이 뛰어나다. 다음 그림은 버클리 데이터베이스가 일반적인 관계형 데이터베이스와 어떤 구조적인 차이점이 있는지 잘 설명해 준다.

일반 관계형 데이터베이스는 독립된 프로그램으로 구성되어 애플리케이션과 따로 동작하면서 애플리케이션과 네트워크가 ‘inter process communication’을 통해 자료를 주고받는다. 하지만 버클리 데이터베이스는 컴파일 시 애플리케이션에 링크되어 애플리케이션의 메모리 어드레스를 함께 사용한다. Locking, 로그 관리, 메모리 관리 등과 같은 기본적인 모든 데이터베이스의 작동이 라이브러리 내에서 수행되고, 멀티 프로세스 또는 프로세스에 있는 멀티 쓰레드는 동시에 데이터베이스를 사용할 수 있다.
결과적으로 프로세스 간 통신이 사라지게 되어 시스템의 전체적인 구조가 간단해진다. 당연히 버클리 데이터베이스는 일반적으로 널리 사용되고 있는 언어인 Java, C, C++, Perl, Tcl, Phthon 그리고 PHP의 API를 제공해 준다.

또한 버클리 데이터베이스는 많은 플랫폼을 지원한다. 모든 유닉스와 리눅스 플랫폼, MS-Windows 플랫폼, 32bit, 64bit 플랫폼, 하이엔드 인터넷 서버(High-end Internet Server)나, 데스크톱 시스템, 노트북 등 모든 곳에서 운용이 가능하다고 볼 수 있다.

버클리 데이터베이스는 다음과 같은 기본적인 기능을 수행한다.

 

1. Page cache management
불필요한 I/O를 줄임으로써 빠른 데이터 접근을 지원한다.
2. Transaction and logging
데이터베이스 복구를 보장한다.
3. Locking
여러 사용자에 의한 다중 읽기 및 쓰기(multiple read/write)를 보장한다.

특히, 일반적인 관계형 데이터베이스와 차별화된 내용은 다음과 같다.

1. SQL 개념의 질의문은 지원되지 않는다.
2. 객체 지향적(Object Oriented)으로 설계되어 있지 않다.(버클리 데이터베이스는 C로 짜여졌다).
3. Network 기능이 없다.
4. 데이터베이스 서버가 아니다.

현재 버클리 데이터베이스는 4.2.X가 최신 버전이다. 비록 프리웨어지만, DB라는 이름에 걸맞게 여러 유틸리티 프로그램도 함께 제공한다.

#ls bin
db_archive*
db_checkpoint*
db_deadlock*
db_dump*
db_load*
db_printlog*
db_recover*
db_stat*
db_upgrade*
db_verify*

 

라이브러리의 구조는 다음과 같다.

#ls lib
db.jar
libdb-4.2.a
libdb-4.2.la
libdb-4.2.so*
libdb-4.so@
libdb.a
libdb.so@
libdb_java-4.2.a
libdb_java-4.2.la
libdb_java-4.2.so*
libdb_java-4.2_g.so@
libdb_java-4.so@
libdb_java.so@

해더 파일들은 무척이나 간단하다.

#ls include
db.h
db_cxx.h

 

버클리 데이터베이스는 데이터를 어떻게 관리할까? 먼저 데이터의 구조는 무척이나 간단하다. 데이터 파일에 저장되는 레코드의 구조는 다음과 같다.

SQL의 테이블, 컬럼 구조에 익숙한 개발자라면 위 표에서 Key, Value 구조의 막막함이 느껴질 것이다. 하지만 잘 짜여진 데이터 구조가 바탕에 있다면 Key, Value의 간단, 명료함은 그 가치를 나타낼 것이다.
위의 구조는 Java 객체중 Properties 객체와 유사하다. 이 구조를 바탕으로 데이터베이스는 레코드 삽입, 삭제, 수정, 그리고 찾기 기능을 수행한다.
여기서 알아두어야 할 중요한 사항은 Value 부분에 대해서는 전혀 오퍼레이션을 하지 않는다는 것이다. Value는 Key로 구분되는 데이터일뿐이다. 이는 Value 부분에 대한 찾기 기능이 없다는 뜻으로 특정 Value를 찾고자 한다면 그 Key 값이 무엇인지를 먼저 알아야 한다.

Key와 Value에 대한 특징은 다음과 같다.

1. Byte 형태의 값을 갖는다.
2. 길이는 고정적이거나 가변적이다.
3. Key나 Value에 대한 형태는 프로그래머에 의해 결정된다.
4. 최대크기는 4GB

네 가지 주요 특징 가운데 세 번째 특징은 프로그래머에게는 부담이 될 수도 있다. 버클리 데이터베이스는 Key와 Value를 의미가 없는 단순한 ‘byte string’으로 인식하고 그에 대한 정보를 하나도 갖고 있지 않기 때문이다. 따라서 Key와 Value가 의미를 갖기 위해서는 프로그래머가 미리 구조를 설계한 후 그 구조에 맞게 Key와Value 값을 가공하여 사용해야 한다. Key와 Value 구조를 모른다면 그 데이터베이스는 의미없는 Byte 덩어리일 뿐이다.

C나 C++로 개발하는 프로그래머일 경우에는 Struct 문장을 사용하여 Key와 Value 구조를 정의하여 사용할 수 있다. 개발 언어가 Java일 경우에는 Object Serialization을 통해 손쉽게 객체를 처리할 수 있다.

 

Key와 Value에 대한 정보가 없다는 것은 개발자나 애플리케이션의 측면에서 볼 때 넘어야 할 걸림돌이다. 모든 것을 프로그래머가 책임져야 한다. 하지만 이러한 특징을 역으로 생각한다면 Key 값과 Value 값에는 어떠한 값이든 넣을 수 있다는 또 다른 가능성도 같이 제공해 준다. 그림이나 사운드든 파일이나 문서든 데이터 형태에 구분받지 않고 Key와 Value 값으로 사용할 수 있는 셈이다. 물론 대부분의 관계형 데이터베이스도 이러한 기능을 지원해 준다.
지금까지는 버클리 데이터베이스가 일반 관계형 데이터베이스와 어떻게 다른지 간략하게 살펴보았다. 그럼 이제부터는 프로그래머가 맛있어 하는 소스를 맛보도록 하겠다. 다음 프로그램은 버클리 데이터베이스를 사용한 간단한 레코드 삽입 프로그램이다. 얼핏보면, isam을 이용한 자료 처리 프로그램과 유사하다.

● 레코드 입력 프로그램 <코드 1>

프로그램<코드 1>을 라인별로 간단히 설명해 보겠다.

12 라인 - 버클리 데이터베이스를 참조하기 위한 객체를 생성한다.
13 라인 - 에러 메세지가 출력될 스트림을 설정한다.
14 라인 - 에러 메세지에 출력될 메세지 prefix
15 라인 - 데이터 파일을 생성하거나 이미 존재하면 그것을 사용한다.


여기서 Open 함수 API의 정확한 정의는 다음과 같다.

public void open(DbTxn txnid, String file,
String database, int type, int flags, int mode)
throws DbException, FileNotFoundException


4번째 파라미터인 Db.DB_BTREE에 대해서는 다음 기회로 미루겠다.

17~30 라인 - Dbt라는 객체를 통해 데이터 파일에 있는 Key/Value를 사용할 수 있다. 24(29), 25(30) 라인에서는 각각 Byte 데이터와 크기를 설정했다.
33 라인 - Key 값과 Value 값을 데이터 파일에 저장한다. 이때 사용한 플래그는 Db.DB_NOOVERWRITE이다. 이 플래그가 설정되면 이미 존재하는 키 값을 저장할 경우 에러가 발생하고, Db.DB_ KEYEXIST 에러 값을 리턴한다. 기본적으로 버클리 데이터베이스는 오류가 없으면 0을 반환하게 되어 있다. 만약 에러가 발생한다면 0 이상의 값을 반환한다.
36 라인 - 데이터베이스 사용을 마친다. 만약 close를 입력하지 않는다면 저장한 데이터는 파일에 기록되지 않고 사라지게 된다. 이는 저장된 자료가 파일이 아닌 메모리의 캐시 영역에 저장되고 사용되기 때문이다. 따라서 추후 사용을 위해 반드시 close 함수나, sync() 함수를 호출해야 한다.

저장을 했으니, 이제 조회를 할 차례다.

● 레코드 조회 프로그램 <코드 2>

프로그램<코드 2>에 대해 라인별로 간단히 설명해 보겠다.

22, 23, 24 라인 - 데이터 검색을 위해 Key 값에 대해서만 찾고자 하는 값을 설정했다.
30 라인 - get method를 호출하여 검색을 한다. 해당되는 Key 값을 갖는 자료를 발견하면, Value 객체에 해당되는 값이 들어간다.
33 라인 - Value Dbt 객체에서 데이터를 갖고와 String으로 저장한다.

앞서 예로 든 두개의 프로그램은 버클리 데이터베이스의 저장 및 조회 프로그램의 기본적인 구조를 보여준다. 여기서 소개된 예제 프로그램은 기본에 충실한 간단한 것이다. 하지만 버클리 데이터베이스가 그리 간단하게 돌아가는 것은 아니다. 이번에는 소개를 하지 못했지만, 기본적인 사용법을 벗어난 다음과 같은 고급 기능들도 있다.
고급 기능에 대한 자세한 설명은 다음 기회로 미루고 이번에는 버클리 데이터베이스에 대한 첫 소개의 기회로 삼을까 한다.

1. cursor를 사용한 데이터 처리
2. DBEnv 객체를 이용한 데이터베이스 환경 사용
3. 4가지의 데이터 접근 방법(BTREE, HASH, QUEUE, REC_NO)
4. Object 객체화
5. Join 검색
6. Dbt의 파생 클래스
7. Sleepycat의 새로운 collection API
8. 트랜잭션 처리
9. locking
10. 로깅 관리
11. 데이터베이스 복구

 

[출처] 버클리 DB|작성자 힐줘볼까

And

proc 파헤치기

윤 상배

dreamyun@yahoo.co.kr


차례
1절. 소개
2절. 오라클 서버/클라이언트 환경만들기
2.1절. 오라클 서버 가동
2.2절. listener (서버측 설정)
2.2.1절. listener 설정
2.2.2절. listener 가동
2.3절. tnsnames (클라이언트측)
2.3.1절. tnsnames 설정
2.3.2절. 테스트
2.4절. 데이타 베이스 준비하기
3절. Pro *C/*C++ 소개
3.1절. 왜 proc 를 사용하는가
3.2절. proc 컴파일 과정
4절. 간단한 proc 프로그램 예제
4.1절. 컴파일 하기
4.2절. 컴파일 과정을 Makefile 로 관리하기
5절. 결론

1절. 소개

proc 프로그래밍은 간단히 다룰수 있는 주제가 아니다. 그럭저럭 다루려고 한다고 해도 책한권 분량은 다루어야할 주제이다.

그러므로 몇번의 문서에 걸쳐서 proc 프로그래밍에 대한 내용을 다룰것이다. 그렇다고 해서 시중에 나와있는 proc 레퍼런스 수준의 방대하고 세밀한 내용을 다룰것을 기대하지는 말기 바란다. 이 사이트의 대부분의 문서들이 그렇듯이 초기에 문제에 쉽게 접근할수 있는 지침서 역활수준에서 작성될것이다.

깊이 있는 내용은 자신이 직접 - 시중의 책을 이용하던지, 아니면 프로젝트를 진행하든지 - 익혀나가도록 해야 할것이다.

이번장에서는 proc 에 대한 간략한 소개와 프로그래밍을 위한 환경설명과, 환경준비과정 그리고 간단한 셈플예제와 이 셈플을 제대로 컴파일 하기 위한 Makefile 제작등에 대해서 알아볼 것이다.

이 문서는 여러분이 적어도 오라클은 설치할줄알고, 기본적인 몇가지 환경정보들은 알고 있다는 가정하에 씌여지게 될것이다. 또한 오라클 817 버젼을 기준으로 작성될것이다. 다른 버젼의 오라클의 경우 경로등에서 약간의 차이가 있을수 있을것이다.


2절. 오라클 서버/클라이언트 환경만들기

proc 프로그래밍을 하기 위해서는 우선적으로 테스트 환경이 만들어져 있어야 한다. 오라클 서버는 이미 설치되어서 가동중에 있다고 가정을 하겠다. 설치 문서는 오라클817 설치하기를 참조하기 바란다.

우리가 proc 를 이용해서 만들고자 하는 프로그램은 c/s 모델기반으로 클라이언트로 작동하게 될것이다. 서버는 오라클이 될것이며, 클라이언트로써 오라클 서버에 접근해서 원하는 정보를 가져오는 프로그램을 만들것이다.

서버/클라이언트 프로그래밍 환경에 있어서 가장 기본적인 것은 서버와 클라이언트의 네트웍 설정을 하는 것이다. 서버측 프로그램은 연결을 받아들일 클라이언트의 주소영역과 포트를 지정하고 클라이언트측에서는 연결을할 서버의 주소영역과 포트번호를 역시 지정해야 할것이다.

일반적인 c/s 모델 프로그램에서는 이러한 정보를 클라이언트 프로그램과 서버 프로그램이 가지고 있지만 오라클의 경우 이러한 네트웍 정보를 자체적으로 유지한다. 이게 바로 listener 와 tnsname 이라는 것이다.

이제 listener 와 tnsname 에 대해서 자세히 알아보도록 하겠다. 참.. 물론 그전에 오라클 서버를 가동 시켜놓아야 한다.


2.1절. 오라클 서버 가동

oracle 계정으로 스위치 유저한다음에 svrmgrl 을 이용하면 간단하게 오라클 서버를 가동시킬수 있다.

Server Manager complete.
[oracle@localhost admin]$ svrmgrl

Oracle Server Manager Release 3.1.7.0.0 - Production

Copyright (c) 1997, 1999, Oracle Corporation.  All Rights Reserved.

Oracle8i Enterprise Edition Release 8.1.7.0.1 - Production
With the Partitioning option
JServer Release 8.1.7.0.1 - Production

SVRMGR> connect internal
Connected.
SVRMGR> startup
ORACLE instance started.
Total System Global Area                         93675680 bytes
...
...
Database opened.
SVRMGR> 
			
SVRMGR 프롬프트가 떨어지고 나면 connect internal -> startup 으로 오라클을 가동시킬수 있다. 중지는 connect internal -> shutdown 이다.


2.2절. listener (서버측 설정)

아마도 listener 이라는 단어에서 대충 어떤 일을 하는 것인지 유추할수 있을것이다. 즉 네트웍 서버로써 외부의 연결이 있는지 대기 하고 있다가 연결이 있으면 연결을 받아들이는 역활을 한다. 연결을 받고 나면 몇가지 처리를 한후 클라이언트를 위한 오라클 인스턴스를 할당하고 만들어진 인스턴스를 이용해서 클라이언트와 대화하게 된다.

이러한 과정을 완전히 이해할려면 더 많은 내용이 보충되어야 하겠지만 이 문서는 DBA 를 위한 문서는 아님으로 이런거다 라는 정도로 이해하는 수준에서 넘어가도록 하겠다. 좀더 깊이 있는 내용에 관심이 있다면 관련 책을 사서 공부해야 할것이다.

간단히 말하자면 listener 은 인터넷 서비스를 위한 오라클 프로세스 라고 생각할수 있는데, 모든 (제대로된) 서버 프로그램이 그렇듯이 이 listener 역시 설정 파일을 가지고 있다.


2.2.1절. listener 설정

$ORACLE_HOME/network/admin/listener.ora 가 바로 listener 설정 파일이다. 다음은 필자의 listener 의 초기 설정치 내용이다.

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
      )
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
      )
    )
  )

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /usr/u01/product/8.1.7)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (GLOBAL_DBNAME = oracle)
      (ORACLE_HOME = /usr/u01/product/8.1.7)
      (SID_NAME = oracle)
    )
  )
				
그리 이해하기 어렵지 않을 것이다. 크게 2개의 섹션으로 이루어 져있는데 LISTENER 섹션은 연결을 받아들일 클라이언트를 위한 호스트 IP 와 PORT 지정을 위한 내용을 SID_LIST_LISTENER 은 서비스할 DB 의 정보를 가지고 있다.

초기에는 단지 localhost(127.0.0.1) 에서의 접근과 내부(IPC) 접근 만을 위한 설정이 되어있다. 기본적으로 오라클은 포트번호 1521 을 사용한다. 어드레스가 더 추가된다면

      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = xxx.xxx.xxx.xxx)(PORT = 1521))
      )
				
이런 식으로 목록을 써나가면 된다.

서비스하는 DB 는 최초에 우리가 만들었던 oracle 이 서비스 될것이다. 마찬가지로 서비스할 DB 목록을 계속적으로 추가해 나갈수 있다.


2.2.2절. listener 가동

listener.ora 설정을 마쳤다면(우선은 초기 기본 설정내용을 그대로 사용하도록 하겠다) 이제 listener 을 가동시켜야 한다. oracle 계정으로 스위치 유저한다음에 lsnrctl 을 사용하면 리스너를 가동시킬수 있다.

[oracle@localhost admin]$ lsnrctl

LSNRCTL for Linux: Version 8.1.7.0.0 - Production on 30-OCT-2002 00:34:12

(c) Copyright 1998 Oracle Corporation.  All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> start
Starting /usr/u01/product/8.1.7/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 8.1.7.0.0 - Production
System parameter file is /usr/u01/product/8.1.7/network/admin/listener.ora
Log messages written to /usr/u01/product/8.1.7/network/log/listener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC)))
...
...
The command completed successfully
				
LSNRCTL> 프롬프트 상에서 status 를 이용하면 현재 리스너의 상태를 확인할수 있으며, stop 를 이용해서 리스너를 중지 시킬수 있다.


2.3절. tnsnames (클라이언트측)

이제 클라이언트측 설정을 해야 한다. 당연히 클라이언트측 호스트에는 Oracle 클라이언트 제품군이 설치되어 있어야 한다(설치되어 있다고 가정하고 문서를 진행 하겠다).

tnsnames 는 간단히 생각하자면 클라이언트 어플리케이션이 오라클 서버에 접근하기 위해서 알아야될 서버측 정보를 담고 있는 데이타베이스라고 알고 있으면 된다.


2.3.1절. tnsnames 설정

$ORACLE_HOME/network/admin/tnsnames.ora 라는 파일이 바로 서버정보를 담고 있는 파일이다.

INST1_HTTP =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = SHARED)
      (SERVICE_NAME = oracle)
      (PRESENTATION = http://admin)
    )
  )

EXTPROC_CONNECTION_DATA =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
    )
    (CONNECT_DATA =
      (SID = PLSExtProc)
      (PRESENTATION = RO)
    )
  )

ORACLE =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = oracle)
    )
  )
				
역시 이해하는 데에는 별로 어려움이 없을것이다. 다른건 별로 신경쓸것 없고 마지막에 있는 ORACLE 정도만 알고 있으면 될것이다. 여기에 보면 접근할 서버의 정보들이 나와 있다. listener.ora 와 비교하면 쉽게 이해가 가능할 것이다. localhost 로 접근하며 1521 포트로 tcp 연결을 하고 oracle DB를 사용하겠다는 정보를 가지고 있다. 만약에 서버측에 zipcode 라는 DB 가 있고 zipcode 에 연결하기 위한 내용을 추가하고 싶다면 아래와 같이 추가시켜주면 될것이다.
ORACLE =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = zipcode)
    )
  )
				
물론 listener.ora 에도 여기에 알맞는 설정이 되어있어야 할것이다.


2.3.2절. 테스트

그럼 간단히 테스트를 해보도록 하자. 테스트는 sqlplus 라는 오라클에서 제공하는 클라이언트 프로그램을 이용할것이다.

 
[oracle@localhost admin]$ sqlplus system/manager@ORACLE

SQL*Plus: Release 8.1.7.0.0 - Production on Wed Oct 30 00:51:35 2002

(c) Copyright 2000 Oracle Corporation.  All rights reserved.


Connected to:
Oracle8i Enterprise Edition Release 8.1.7.0.1 - Production
With the Partitioning option
JServer Release 8.1.7.0.1 - Production

SQL> 
				
SQL> 프롬프트가 떨어진다면 listener 가 제대로 작동하며 해당 tnsnames 를 이용해서 연결을 성공했음을 의미한다.


2.4절. 데이타 베이스 준비하기

그럼 테스트를 위한 데이타베이스를 준비해 보도록 하자. 준비할 데이타 베이스는 우편번호이다. 자료실에서 다운로드 받을수 있다.

압축을 풀면 10개 정도의 파일이 생성될것인데, 오라클에서 곧바로 읽어들일수 있다. sqlplus 를 이용해서 oracle db 에 접근하도록 한다. 그다음 "@파일이름" 식으로 적재하면 된다.

  
SQL> @postcode.sql
Input truncated to 3 characters

Table created.

SQL> @postcode1.sql 
...
SQL> @postcod2.sql
			
이로써 테스트용 db 생성까지 모두 마쳤다. 적재하기가 귀찮다면 그냥 테스트용으로 파일 하나 분량 정도만 적재해도 관계는 없다.


3절. Pro *C/*C++ 소개

Pro *C(이하 proc) 는 일종의 프리컴파일러다. 즉 C코드에 오라클관리를 위해서 일상적으로 사용하는 SQL, PL/SQL 등을 결합시켜서 코딩된 프로그램을 C컴파일러(여기에서는 gcc)가 인식할수 있는 C 코드 파일로 변경시켜주는 일을 한다. 오라클에서는 proc 라는 프리컴파일러를 제공하고 있다.


3.1절. 왜 proc 를 사용하는가

아마도 1GL 이니 2GL 이니 하는 프로그래밍 언어 세대를 나타내는 말에 대해서 들어 보았을것이다. 보통 1세대 언어, 2세대 언어라는 식으로 불리는데, 이 분류에 따르면 C 언어는 3세대 언어(3GL)이다. 이에 반해 SQL(Structur query language) 언어는 4세대 언어로써, 3GL 언어가 절차식 언어인데 반해서, 4세대 언어는 좀더 자연어에 근접한 언어적 특성을 가진다.

이러한 4GL 언어가 가지는 자연어에 근접한 특성은 언어 사용을 직관적이고 쉽게 할수 있도록 만들어주지만, 절차지향 적인 업무를 처리하기에는 그리 적합하지가 않다. 그래서 많은 경우 C, C++, JAVA 등의 언어들과 결합해서 사용 하게 된다.

그런데 대게의 경우 이러한 3GL언어와 4GL 언어의 결합과정은 꽤나 성가신 작업이며, 많은 시간을 필요로 한다. SQL 은 별도로 하고, 거기에 덧붙여서 다양한 API 들을 새로 익혀야 하기 때문이다. 그나마 mysql, postgresql 과 같은 비교적 단순한(오라클에 비해서) DB의 경우 몇가지 API 만 익힘으로써 그리 어렵지 않게 프로그래밍 할수 있지만, 오라클의 경우 상당한 노력을 필요로 한다. 이러한 저수준에서 직접접근을 위해서 제공하는게 OCI(Oracle Call Interface) 라는 API 모음이다.

그래서 높더 높은 레벨에서 C 언어와 SQL 언어를 결합해서 프로그래밍 할수 있는 환경을 제공하고자 하는 목적에서 나온게 바로 proc 이다. proc 소쓰를 보면 알겠지만 복잡한 API 들 대신에 SQL 의 문장을 그대로 사용하고 있음을 알수 있다.

또한 proc 는 C 코드네에 PL/SQL 블럭을 직접 넣어서 코딩할수 있도록 되어 있다. PL/SQL 은 4GL 언어의 자연어적인 특성에 절차식 언어인 3GL 언어의 특징을 결합시킨 도구이다. PL/SQL 에 대한 내용은 자세히 다루지는 않을것이며, 필요할경우 약간씩 다루도록 하겠다. 어쨋든 proc 를 이요한 프로그래밍을 하려면 PL/SQL 에 어느정도 익숙해질 필요가 있다. PL/SQL 은 4GL 언어의 특성을 가지므로 C, JAVA 등에 비해서 매우 쉽게 익힐수 있다.


3.2절. proc 컴파일 과정

일단 프로그래머는 SQL 문이 포함되어 있는 코드를 작성한다. 보통이러한 코드는 확장자가 .pc 로 되어있다. 그러나 이러한 .pc 코드는 gcc 컴파일러가 컴파일 할수 없음으로 gcc 가 이해할수 있는 .c 코드로 변경시켜주는 "선행컴파일" 과정이 필요하다. 이 선행컴파일러거 .pc 파일을 .c 코드로 변경한 이후의 컴파일 과정은 기존 c 컴파일 과정과 완전히 동일하다.

     +--------------+
     | Proc Program | SQL 문을 포함
     | .pc          | 
     +--------------+
            ↓
     +--------------+
     | 오라클       | 
     | 선행컴파일러 | 
     | proc         |
     +--------------+
            ↓
     +--------------+
     | 해석된       | 기존의 SQL 문은 library 를 
     | .c 쏘쓰코드  | 직접 호출하는 문으로 변경됨 
     +--------------+
            ↓
     +--------------+
     | C 컴파일러   | 
     +--------------+
            ↓
     +--------------+
     | Object 파일  | 
     +--------------+
            ↓
     +--------------+
     | Linker       | 오라클 라이브러리가 링크됨 
     +--------------+
            ↓
     +--------------+
     | 실행파일     | 
     +--------------+

			


4절. 간단한 proc 프로그램 예제

다음은 zipcode 테이블에 총몇개의 자료가 들어있는지 알아오는 아주 간단한 프로그램이다.

예제 : zipcode.pc

 
#include <stdio.h>
#include <unistd.h>

/* SQLCA 를 선언한다 */
EXEC SQL INCLUDE SQLCA;

int main(int argc, char **argv)
{
    /* 선언부 */
    EXEC SQL BEGIN DECLARE SECTION;
            int count = 0;
            char userid[40]= "system/manager@ORACLE";
    EXEC SQL END DECLARE SECTION;

    /* DB 연결 */
    EXEC SQL CONNECT :userid;

    /* 에러 처리 */
    if (sqlca.sqlcode < 0)
    {
            printf("%s\n", sqlca.sqlerrm.sqlerrmc);
            EXEC SQL ROLLBACK WORK RELEASE;
            exit(0);
    }

    /* 쿼리 */ 
    EXEC SQL SELECT count(*) 
            INTO: count  
            FROM zipcode;

    /* 쿼리 결과에 대한 에러처리 */
    if (sqlca.sqlcode != 0) 
    {
            EXEC SQL COMMIT WORK RELEASE;
            return 0;
    }

    printf("우편주소 데이타 : %d 개\n", count);

    /* DB 연결 종료 */
    EXEC SQL COMMIT WORK RELEASE;
}
		
코드를 보면 알겠지만 뭐 복잡하게 이것 저것 인클루드 시켜줄 필요도 없고, SQL 문이 거의 그대로 쓰여서 이해하기도 매우 쉽다는 것을 알수 있을 것이다. 참고로 오라클 proc 쏘쓰파일에서의 주석은 /* */ 만 사용가능하다. // 을 썼다가는 오류가 발생한다.

이번 문서는 단지 이런식으로 프로그래밍이 가능하다라는 정도만 보여줄 것임으로 위의 코드의 설명은 생략하도록 하겠다. 나중에 자세히 다루도록 하겠다.


4.1절. 컴파일 하기

우선 zipcode.pc 파일을 proc 선행 컴파일러를 이용해서 zipcode.c 파일을 얻어낸다음 gcc를 이용해서 object 파일을 만들고 링크과정을 거쳐서 실행파일을 만들어야 한다. 다음은 이러한 일련의 과정이다.

[oracle@localhost proc]$ proc zipcode INCLUDE=include/ \ 
> include=/usr/u01/product/8.1.7/precomp/public/ \
> include=/usr/u01/product/8.1.7/rdbms/demo/ \
> include=/usr/u01/product/8.1.7/rdbms/public/ \
> include=/usr/u01/product/8.1.7/network/public/ \
> PARSE=NONE RELEASE_CURSOR=YES MODE=ANSI

Pro*C/C++: Release 8.1.7.0.0 - Production on Thu Oct 31 00:29:15 2002

(c) Copyright 2000 Oracle Corporation.  All rights reserved.

System default option values taken from: /usr/u01/product/8.1.7/precomp/admin/pcscfg.cfg

[oracle@localhost proc]$ gcc -c -o zipcode.o zipcode.c -I$ORACLE_HOME/precomp/public \ 
> -I$ORACLE_HOME/rdbms/demo -I$ORACLE_HOME/rdbms/public \
> -I$ORACLE_HOME/network/public

[oracle@localhost proc]$ gcc -o zipcode zipcode.o -L$ORACLE_HOME/lib -lclntsh
			
이 프로그램을 실행시키면 다음과 같은 결과값을 보여줄 것이다.
[oracle@localhost proc]$ ./zipcode 
우편주소 데이타 : 43476 개
			


4.2절. 컴파일 과정을 Makefile 로 관리하기

하지만 위의 방법대로 수동으로 코드를 컴파일 하는건 비 생산적인 방법이다. 그러므로 Makefile 을 만들어서 관리하도록 하자.

Makefile

TARGET          = zipcode

CC              = gcc
PROC            = proc
LIB             = -L$(ORACLE_HOME)/lib -lclntsh
MYINC           = include/
PROCINC         = include=$(ORACLE_HOME)/precomp/public/ include=$(ORACLE_HOME)/rdbms/demo/ \
	include=$(ORACLE_HOME)/rdbms/public/ \
	include=$(ORACLE_HOME)/network/public/ 
CINC            = -I$(ORACLE_HOME)/precomp/public/ -I$(ORACLE_HOME)/rdbms/demo/ \
	-I$(ORACLE_HOME)/rdbms/public/ -I$(ORACLE_HOME)/network/public/ 

ORA_OPT         = PARSE=NONE RELEASE_CURSOR=YES MODE=ANSI
CC_OPT          =

OBJECT          = zipcode.o
ORA_GARBAGE     = *.dcl *.cod *.cud *.lis

######## implicit rules
.SUFFIXES: .pc .c

.pc.c:
	$(PROC) $* INCLUDE=$(MYINC) $(PROCINC) $(ORA_OPT)
.c.o:
	$(CC) -c -o $*.o $*.c -I $(MYINC) $(CINC)

####### build rules

all:            $(TARGET)

$(TARGET):      $(OBJECT)
	$(CC) -o $(TARGET) $(OBJECT) $(LIB)

zipcode.c: zipcode.pc
zipcode.o: zipcode.c

clean:
	rm -f $(TARGET) $(OBJECT) $(ORA_GARBAGE)
			
이해하는데 특별히 어려움은 없을것이라고 생각된다. Makefile 에 대한 내용은 make 를 이용한 프로젝트 관리 (1)를 참고하도록 한다.


5절. 결론

이상 proc 프로그래밍을 위한 가장 기본적인 환경에 대해서 알아보았으며, 아주 간단한 예를 들어서 proc 프로그래밍을 맛보았다. 다음에는 좀더 자세한 proc 프로그래밍에 관한 내용을 다루도록 하겠다.

And