글
| ||
1. Large Object란 무엇인가? Large Object는 우리말로 표현하면 거대 객체라고 할 수 있겠다. PostgreSQL에서는 기본 데이터 페이지가 8K(8192바이트)로 한정되어 있다. 이제 데이터 저장측면에서 생각해보자. 우리가 다루기를 원하는 데이터가 8K 보다 크다고 하더라도 거대객체를 사용하지 않더라도 처리할 수 있는 경우가 있다. 가령 이미지를 다루는 경우를 생각해본다면, 이미지에 대한 각종 정보는 테이블에 저장하고 실제 이미지 파일은 파일 시스템에 파일로 그냥 저장할 수 있다. 이럴 경우에 사용자가 이미지 파일을 검색하기를 원한다면 테이블 정보에서 원하는 키워드로 검색을 한다. 음, 이에 해당하는 파일 시스템상의 이미지 파일을 일반 UNIX 파일 처리 함수를 사용하여 읽어들일 수 있다. 물론, 원한다면 웹 브라우저 상에 그냥 출력할 수도 있다. 일반적으로 자주 사용하는 방법이, 이렇게 원하는 거대 데이터를 파일 시스템상에 저장하고 이에 대한 정보만 테이블에 저장하는 것이다. 이렇게만 사용한다면 거대객체를 굳이 사용할 필요는 없어진다. 그리고 이 경우에 이미지 파일은 엄밀히 따진다면 RDBMS의 외부에 있다고 볼 수 있다. 따라서 데이터베이스의 관리 측면에서 볼 때, 데이터베이스의 외부에 있음으로 인해 데이터의 무결성이 보장되지 않고, 검색 등의 작업에 있어서 데이터베이스의 효율성을 활용할 수 없다는 단점이 있다. 이러한 단점은 RDBMS의 사용에 있어서 치명적인 손해가 아닐 수 없다. 이로 인해 등장한 것이 거대객체이다. 그림에서 알 수 있듯이 RDBMS는 내부 저장 시스템을 가지고 있다. 거대 데이터의 경우에는 파일 이미지는 데이터베이스의 내부 저장 메카니즘에 따라 저장시스템에 분리되어 효율적으로 저장되며, 이에 대한 정보는 테이블 내의 객체 식별자(oid)와 연결되어 유지하는 것이다. Oid는 PostgreSQL 서버가 데이터베이스 내의 모든 인스턴스에 자동적으로 부여하는 중복되지 않는 유일한 식별자이다. 거대객체 메카니즘을 사용할 때의 장점은 데이터의 무결성을 보장하고, 검색시에 데이터베이스의 효율성을 확보할 수 있다는 점 외에도 시간여행(time travel) 기능을 제공한다. UNIX 파일 시스템에서 파일이 지워지면 끝장이지만, PostgreSQL 데이터베이스 서버 내에서 지운 파일은 완전히 지워진게 아니라서 시간여행을 통해 고스란히 복구할 수 있다. PostgreSQL 서버의 거대객체의 최대 단점은 일반 UNIX 정규파일을 거대객체 내에 흡수하기 위하여 필요한 수입(import)과 수출(export)시에 많은 시간이 걸린다는 것이다. 수 메가 바이트 이상의 파일을 다룰 때, 수입은 한 번만 하겠지만 수출은 여러 번 하게 될 것이다. 사용자에게 온라인으로 데이터를 디스플레이해야 할 경우가 자주 발생할 것이기 때문이다. 이럴 경우에는 차라리 거대객체를 사용하지 않는 것이 좋다고 생각한다. 너무 자주 수출을 하게 되면 파일을 복사하는 것 이상의 자원을 잡아먹기 때문이다. 또 한가지는 누구나 느끼는 문제겠지만 좀 번거롭다는 것이다. 테이블 내에 필요한 모든 데이터를 저장하는 것이 아니라 객체 식별자만 저장하고 정작 데이터는 데이터베이스 내부의 별도의 저장시스템에 저장한다는 것도 그렇고, 수입(import)과 수출(export)이 필요하다는 점도 그렇다. ☞ 거대객체를 설명할 때 사용되는 import와 export를 대체할 적당한 우리말이 없는 것 같아, 2. 멀티미디어 데이터와 검색 굳이 멀티미디어뿐만이 아니라 8K를 넘어가는 문자, 숫자, 통계 데이터 등을 다루는 데에도 거대객체를 사용할 수 있음을 앞서 언급하였다. 그리고 이들 거대객체를 사용하는 데이터는 oid를 통해서 접근할 수 있다고 언급하였다. 멀티미디어든지 아니던지 이들 거대객체 데이터의 검색이나 수정은 모두 동일할 것이다. 거대객체에 대한 주변적인 정보는 기본 테이블에 저장할 것이지만 본격 거대객체 데이터는 테이블 내의 oid를 통해 접근될 것이기 때문이다. 따라서 이들 데이터를 검색하는 방법은 대체로 두 가지가 있다고 볼 수 있다. 단순히 주변적인 테이블 데이터를 검색하는 방법과 테이블 내의 oid 필드를 통하여 거대객체 데이터를 직접 검색하는 방법이다. 거대객체 인터페이스를 사용하는 데이터의 유형이 여러 가지가 있겠지만 여기서는 논문을 관리하는 데이터베이스의 예를 들어보자(그 외의 멀티미디어 데이터도 마찬가지일 것이다). 먼저, 논문이라는 테이블을 하나 만들 것이고, 필드는 대략 지은이, 날짜, 제목, 자료명, 크기, 형식, OID 정도가 될 것이다. 외부 논문 파일을 수입(import)하면서 테이블의 나머지 항목을 채우게 될 것이다. 물론 수입(import)시에 반환하는 oid를 테이블의 OID 필드에 저장함으로써 oid를 통해 거대객체에 접근할 수 있다. 이제 기본 골격은 다 만들어졌다고 가정하자(자세한 방법은 이후에 설명한다). 사용자가 검색을 원할 때에는 테이블 내의 어느 한가지 이상의 항목을 사용하겠지만, 편의를 위해 제목을 통해 검색하고 싶어한다고 가정한다. SELECT를 사용하여 논문 테이블의 제목 필드에서 원하는 레코드를 찾았다면, OID 필드를 통해 거대객체에 접근할 것이다. 이 부분에서 거대객체를 어떻게 다루느냐에 따라 두 가지 접근 방법이 있다고 할 수 있다. ▶ 논문이라는 거대객체에 대한 접근을 하지 않는 방법이다. 보통 이 경우가 많이 사용될 것 ▶ 다른 하나의 방법은 논문(거대객체)에 직접적으로 접근하는 방법이다. 논문이 ps 파일 3. 거대객체의 인터페이스 거대객체에 대한 인터페이스는 주로 C언어로 작성된 함수이다. 거대객체와 관련된 모든 작업은 거대객체 인터페이스를 통해야 한다. PostgreSQL에서는 SQL에서 유용하게 사용할 수 있는 수입(import)과 수출(export) 함수를 지원한다. 이들 함수는 PostgreSQL 내부에 미리 등록이 되어 있어 바로 사용할 수 있다. 여기서는 먼저 PostgreSQL 내부에 등록되어 있는 수입(import)과 수출(export)에 관련된 함수를 살펴보도록 한다. 1) SQL 내부 등록 함수 PostgreSQL 내부에 등록되어 있는 함수는 lo_export 이다. lo_import는 수입을 담당하고 lo_export는 수출을 담당한다. lo_import의 반환값은 수입을 한 거대객체의 oid(객체 식별자 타입)이고 lo_export의 반환값은 수행결과의 성공여부를 나타내는 참 거짓값이다. 이 두 함수를 사용하면 수입과 수출은 C함수를 사용하지 않고도 할 수 있으므로, 거대객체에 대한 직접적인 검색을 하지 않는 경우라면 거대객체의 C 인터페이스를 전혀 사용하지 않아도 거대객체를 기본적으로 다룰 수 있다.
2) C 인터페이스 거대객체의 C 인터페이스에는 거대객체를 다루는 데 필요한 거의 모든 함수들이 포함되어 있다. 앞서 언급한 거대객체의 수입과 수출을 다루는 lo_import와 lo_export, 거대객체를 만들고(lo_creat), 열고(lo_open), 닫고(lo_close), 이동하고(lo_lseek), 쓰는(lo_write) 함수들이 있다. 거대객체를 다루는 기본적인 함수는 표준 UNIX의 저급 파일 기술자를 다루는 함수들과 그 이름의 앞부분에서 lo_만 빼면 동일하다. 여러분들은 이러한 lo_류의 함수를 사용하여 마치 UNIX 파일 시스템에서 파일을 만들고(creat), 열고(open), 이동하고(lseek), 쓰고(write), 닫는(close)것처럼 이러한 거대객체 인터페이스를 통해 거대객체에 대해서도 동일한 작업을 할 수 있다. UNIX 파일과 거대객체라는 대상만 다를 뿐이지 적용되는 개념과 실제 사용법은 동일하므로 거대객체라는 사실에 대해 너무 걱정하지 말기를 바란다. 그럼 거대객체의 C 인터페이스 함수를 하나씩 살펴보고, 이후에 이들 함수를 사용하는 간단한 예제를 보도록 하겠다. 거대객체의 생성 Oid lo_creat (PGconn *conn, int mode) 이 함수는 거대객체를 생성하여 그 oid(객체 식별자 타입)를 돌려준다. UNIX의 creat 함수와 마찬가지로 그냥 빈 거대객체를 생성한다고 보아도 좋다. 실제로는 거의 쓰이지 않는다. 거대객체의 생성은 주로 수입(lo_import)을 통하여 만들어지기 때문이다. 거대객체의 수입 Oid lo_import (PGconn *conn, text *filename) 앞서 설명한 거대객체를 수입(import)하는 함수이다. filename 이라 불리는 파일을 수입하여, 그 oid(객체 식별자 타입)를 반환한다. 파일 시스템상에 존재하는 외부 데이터 파일을 데이터베이스 내부에 가지고 올 때 사용된다. 거대객체의 수출 int lo_export (PGconn *conn, Oid large_object_id, text *filename) 앞서 설명한 거대객체를 수출(export)하는 함수이다. oid(거대객체 식별자)로 large_object_id를 가지는 거대객체를 외부 파일 시스템상에 filename이라는 이름으로 끄집어 낸다. 되돌림 값은 수출의 성공여부를 나타내는 참 거짓값이다. 거대객체를 열기 int lo_open (PGconn *conn, Oid large_object_id, int mode, ...) large_object_id는 열려는 거대객체 식별자이다. mode는 읽기(INV_READ)나 쓰기(INV_WRITE), 또는 둘 다를 지정할 수 있다. 존재하지 않는 거대객체를 lo_open으로 열 수는 없다. lo_open의 반환값은 거대객체 기술자(UNIX의 저수준 파일 기술자와 동일시하기 바란다)로, 나중의 lo_read, lo_write, lo_write, lo_lseek, lo_tell, lo_close 함수에서 인자로 사용된다. 거대객체에서 읽어오기 int lo_read (PGconn *conn, int fd, char *buf, int len) 거대객체 기술자 fd에서 len 길이만큼 읽어서 buf에 저장한다. 거대객체에 쓰기 int lo_write (PGconn *conn, int fd, char *buf, int len) 이 함수는 buf에서 len 길이만큼의 바이트를 현재의 거대객체 기술자인 fd에 쓴다. 당연한 이야기겠지만 fd는 이전의 lo_open에서 반환된 값이어야 한다. lo_write의 반환값은 실제로 쓰여진 바이트 수이다. 만일 에러가 발생하였다면 음수를 돌려준다. 거대객체 내부에서의 이동 int lo_lseek (PGconn *conn, int fd, int offset, int whence) 이 함수는 기술자 fd로 표현되는 거대객체 내부에서 현재의 읽기/쓰기 위치를 변경하는 데 사용된다. offset은 이동거리이다. whence는 UNIX의 lseek처럼 SEEK_SET, SEEK_CUR, SEEK_END를 사용할 수 있다. 거대객체 내부에서의 위치 파악 int lo_tell (PGconn *conn, int fd) 현재의 거대객체의 기술자인 fd에서의 위치를 돌려준다. 거대객체를 닫기 int lo_close (PGconn *conn, int fd) 이 함수는 거대객체 기술자 fd를 닫는 역할을 한다. lo_close가 성공적으로 수행되면 0을 돌려주고, 에러시에는 음수값을 반환한다. 거대객체를 없애기 int lo_unlink (PGconn *conn, Oid large_object_id) 거대객체 식별자로 large_object_id 값을 가지는 거대객체를 내부 저장시스템에서 제거한다. 지금까지 간단하게 거대객체 인터페이스를 살펴보았다. 이들 함수를 사용하기 위해서는 libpq/libpq-fs.h 헤더파일을 포함하여야 한다. 물론 libpq와 링크를 시키는 것이 필요하다. 4. 예제 프로그램의 작성 1) 거대객체를 사용할 것인가 말 것인가 거대객체를 사용하는 응용 프로그램을 어떻게 만들 것인가 하는 문제는 전체적인 설계를 어떻게 할 것인가 하는 문제다. 앞에서도 살펴보았지만 거대객체라고 해서 특별한 것은 없다. PostgreSQL 내부에서 8K 이하의 데이터는 효율적으로 다룰 수 있고, 그 이상의 데이터는 거대객체라는 인터페이스를 사용하는 것뿐이다. 그리고 거대객체에 대한 접근을 보장하기 위해 바로 위에서 설명한 인터페이스를 제공하는 것이다. 여러분들은 거대객체를 사용하는 어플리케이션을 만들고 싶어할 것이다. 여러분이 원하는 데이터를 다루기 위한 데이터베이스를 구축하는데 거대객체가 필요할 수도 있다. 필자의 경우에도 실무 프로그래밍에서는 대부분 거대객체를 사용하지 않았었다. 이유는 단 한가지, 귀찮다는 것이었다. 일거리가 많아진다는 것은 프로그래머에게는 정말 귀찮은 일이다. 여러분이 사용하고자 하는 데이터가 단순히 덩치만 큰 데이터라면 거대객체를 사용하지 않아도 상관없다. 파일의 이름만 테이블에 저장해놓고 필요할 시에는 그 파일을 보여주면 된다. 또한 수출(export)이 자주 발생할 것이라면 이 역시 거대객체를 사용하는 것이 단점이 된다. 수 메가나 되는 용량의 파일을 하루에 여러 수십 번, 아니 여러 수백 번씩 수출(export)을 하기 위해 복사를 하는 것은 어찌보면 대단히 불만스러울 수도 있다. 이런 경우라면 거대객체를 사용하지 않아도 된다는 것을 이야기하고 싶다. 하지만 여러분들의 데이터베이스가 무결성을 보장하는 것을 원하고, 대형의 멀티미디어 데이터를 데이터베이스 서버의 장악권에 확실히 두고 싶다면, 그리고 시간여행, 인덱스와 같은 데이터베이스 서버의 효율적인 기능을 활용하고 싶다면 거대객체를 사용하자. 아울러 여러분들의 멀티미디어 데이터에 대한 확실한 정보를 가지고 있다면, 혹은 이에 대한 검색, 수정 추가에 대한 사용자 정의 함수를 만들 수만 있다면, 거대객체 인터페이스는 여러분들의 과제를 해결하는데 최상의 솔루션을 제공할 것이다. 믿거나 말거나. 2) 간단한 예제 프로그램 앞서 설명한 인터페이스 함수를 사용하여 간단한 예제를 만들어 보자. PostgreSQL 배포 패키지 안의 src/examples/ 디렉토리에 testlo.c라는 예제 프로그램이 있다. 다음에 나오는 예제 프로그램과 함께 살펴본다면 상당한 도움이 되리라 본다. 그리고 인터페이스 함수에 대한 설명을 즉석에서 보고자 한다면 man large_objects 명령으로 매뉴얼 페이지를 참고하는 것도 좋다. 매뉴얼 페이지에는 몇 개의 함수가 빠져있다. lo_tell이나 lo_unlink등이 그렇다. 본 예제프로그램에서는 거대객체 인터페이스 함수의 사용법을 보이기 위한 목적으로 작성한 것이다. 거대객체의 생성 - lo_creat 〔 리스트 1 〕lo.c
컴파일은 다음과 같이 한다. $ gcc -o lo lo.c -I/usr/local/pgsql/include -L/usr/local/pgsql/lib -lpq -g -Wall; 테스트 결과는 다음과 같다. 5. 논문 데이터베이스 구축 예제 앞서 잠시 언급한 논문 데이터베이스를 하나 구축해보자. 처음에는 간단한 XPM 파일을 예제로 다루려고 했으나 좀 더 실용적인 논문 데이터베이스를 다루어 보도록 하겠다. 그리고 거대객체를 사용할 시에 거대객체에 대한 저급적인 접근은 피하도록 하겠다. 이유는 논문 데이터 파일의 형식에 대한 어떠한 제한을 두기에도 좀 그렇고, 저급적인 접근을 하려면 어느 정도 시간 동안의 연구가 필요하다고 보여지기 때문이다. 논문 데이터베이스를 웹과 연동을 할 경우도 무시하지 못하는데, 이럴 경우에 논문 파일 형식에 대한 CGI 필터링이 필요할 지도 모른다. 가까운 예를 하나 들면 PS파일을 CGI 프로그램에서 HTML 파일로 변환하여 실시간으로 웹 브라우저 상에 보여주는 경우를 들 수 있다. (또 하나의 예로 특정 회사의 전유물이긴 하지만 HWP 형식의 파일을 실시간으로 웹 브라우저 상에 HTML로 출력해주는 HWP CGI 서버 등이 있다.) 웹 브라우저 상에서 곧바로 처리하지 못하는 파일 형식을 가지는 거대객체를 웹 상에 출력하려면 이러한 중간 CGI 인터페이스가 필요할 것이다. 이러한 변환은 여러분의 몫이다. 여기서는 거대객체에 대해서는 import와 export만을 사용할 것이다. 나머지 검색은 논문 데이터에 대한 정보를 저장하는 테이블을 통해서 이루어질 것이다. 먼저 데이터베이스에 필요한 테이블을 정의하여 보자. 데이터베이스는 mydb를 사용할 것이고, 테이블은 논문이라고 명명할 것이다. 논문 테이블은 다음과 같이 정의한다. CREATE TABLE 논문 ( 이외에도 테이블에 논문에 대한 설명 필드나 분류코드 등이 들어갈 법하지만 간단하게 하기 위해서 생략하도록 한다. 이제 데이터를 입력해보자. psql의 \copy 명령을 사용하면 보통의 데이터는 쉽게 집어 넣을 수 있는데, lo_import 때문에 되지 않는 것 같다. 귀찮더라도 다음의 명령을 일일이 쳐주기 바란다. 아니면 파일에 담아서 psql의 \i 명령을 사용해도 좋다. 입력 인터페이스는 실제로는 웹을 통하는 것이 제일 간편하고 현대적인 방식일 것이다. 그 외에도 PostgreSQL을 지원하는 X용 프론트 엔드 프로그램을 사용하면 쉽게 할 수 있는 것도 있으니 찾아보기 바란다. lo_import 함수 안의 파일명은 미리 파일 시스템상에 아무 것이나 복사해서 만들어 두도록 하자. INSERT INTO 논문 VALUES ('미식가', '1980-02-20', '바퀴벌레 뒷다리에 대한 영양학적 분석', '바퀴벌레.html', 234500, 'HTML', lo_import('/tmp/바퀴벌레.ps')); INSERT INTO 논문 VALUES ('전일수', '1995-05-05', '객체지향 데이터 모델에서 클라스 계층 및 클라스 합성 계층의 집중화 기법', 'object_class.html', 101010, 'HTML', lo_import('/tmp/object_class.html')); INSERT INTO 논문 VALUES ('동석호', '1995-06-30', 'B형 간염 바이러스의 발현 및 증식에 있어서 X 유전자의 역할', 'xgene.html', 41098, 'HTML', lo_import('/tmp/xgene.html')); INSERT INTO 논문 VALUES ('장태성', '1995-09-25', '2단계 디스크 캐쉬 모형에 관한 연구', 'disk_cache.html', 141342, 'HTML', lo_import('/tmp/disk_cache.html')); INSERT INTO 논문 VALUES ('안이기', '1995-10-15', '비정상 박리에 관한 실험적 연구', 'tunnel.html', 874345, 'HTML', lo_import('/tmp/tunnel.html')); 이제 테이블에 데이터가 삽입되었을 것이다. 데이터베이스의 사용자가 특정 인물이나 날짜기간, 제목 등에 대한 검색을 통해서 원하는 논문을 찾고 싶다고 하자. 실제로는 여기에 몇 가지 더 정보가 추가되고 온라인으로 논문 내용을 검색하도록 하는 것이 좋지만, 그럴 여력이 없으므로 간단한 SELECT만 해보도록 한다. 눈으로 확인할 수 있는 것처럼, 거대객체를 외부 파일로 export하였다. 원한다면 사용자가 볼 수 있도록 하거나 내려받기를 하도록 하는 것도 생각해볼 수 있다. ☞ PHP/FI 와 거대객체 얼마 전에 PHP/FI에서 거대객체를 다룰 수 있는 방법이 없느냐는 어느 분의 질문이 있었는데, 깊이 생각해보지 않아서 답변을 드리지 못했다. 결론은 PHP/FI에서 거대객체에 대한 인터페이스는 SQL에서 사용할 수 있는 lo_export와 lo_import 밖에 없다는 것이다. 이것만 사용해도 거대객체의 입출력은 할 수 있으므로 아쉬운 대로 사용할 수는 있다. 하지만 거대객체에 대한 저급적인 접근 방법을 PHP/FI에서 사용할 수 있는 방법은 없다. PHP/FI에서 사용자가 자신의 C언어 정의 함수를 사용할 수 있는 방법이 있긴 하지만, PostgreSQL의 C언어 거대객체 인터페이스를 PHP/FI에 가져다 붙인다는 것은 상당히 힘들다고 볼 수 있다. 결론적으로, PHP/FI에서도 SQL에서와 마찬가지로 멀티미디어 데이터를 데이터베이스 내부에 둘 수는 있다. 하지만 저급적인 접근은 할 수 없으므로 제한이 있을 수밖에 없다. ☞ 지워진 거대객체의 복구 어쩌다가 데이터가 지워지는 원치 않는 경우가 있을 수 있다. 트랜잭션이 살릴 수 없는 데이터도 시간여행을 통해서 라면 살릴 수 있다. 다만 테이블이나 데이터베이스의 삭제가 아닌 테이블 내의 데이터의 삭제이어야 하고, vacuum이 실행되기 전이어야 한다. 이럴 경우에는 다음과 같은 SQL문을 사용하여 원상 복구시킬 수 있다. insert into 논문 select *from 논문['epoch', 'now']; 6. 요약 지금까지 간단하게 PostgreSQL의 거대객체 인터페이스에 관해 살펴보았다. 거대객체에 대한 개념과 거대객체를 사용할 때의 장단점, 거대객체 함수 인터페이스와 실제 사용 예를 살펴보았다. 그리고 상당히 초보적이긴 하지만 간단한 멀티미디어(라고 할 수도 없을 것같지만) 데이터를 거대객체에서 어떻게 다루는지에 대해서도 사례를 통해서 살펴보았다. 사실 이것은 아주 기초적인 것에 지나지 않는다. 실제로 이러한 데이터를 다루려면 웹 인터페이스를 사용하는 것이 현실적이고, 그렇다고 한다면 웹 상에서 멀티미디어 데이터를 출력할 수 있어야 한다. 그게 HTML이 되던 SGML이 되든 간에 데이터베이스를 사용하고자 하는 이에게 최대한의 내용을 보여주는 것이 중요하다고 볼 수 있다. 처음에는 간단하나마 웹 상에서 보여줄 수 있는 자그마한 거대객체 어플리케이션을 작성해보려고 했지만, 짧은 시간 안에 이것저것 하려니 뜻대로 되지 않았다. 정말 리눅스에서는 할 것이 너무 많아 평생을 해도 다 못할 것 같다. :) 아, 이제 아쉬운 설 연휴도 PostgreSQL과 함께 끝나가고 있다. 리눅스 월드에 연재되는 PostgreSQL 기사의 프로그램 소스와 지난 12월에 연재되었던 PHP/FI 프로그램 소스는 필자의 홈페이지(http://free.sense.co.kr/CGI_database/)와 하이텔 리눅스 동호회 자료실에 정기적으로 올려두고 있다. 소스가 필요하신 분은 참고하기 바란다. [출처] 공개 데이터베이스 서버 PostgreSQL (5)|작성자 황제펭귄 |
'PostgreSQL' 카테고리의 다른 글
SPI 와 트리거의 밀월여행 (0) | 2009.06.30 |
---|---|
ECPG로 Embedded SQL 프로그래밍하기 (0) | 2009.06.30 |
libpq를 이용한 어플리케이션 작성 (0) | 2009.06.30 |
공개용 데이터베이스 서버 PostgreSQL (3) (0) | 2009.06.30 |
공개용 데이터베이스 서버 PostgreSQL (2) (0) | 2009.06.30 |
RECENT COMMENT