IT 전용글/Oracle

[DBMS] 윈도우에서의 오라클(oracle 10g) 캐릭터셋(UTF8) 변경

회상형인간 2008. 12. 28. 23:39

윈도우 XP에 오라클을 한국어를 기본적으로 선택해서 설치하였다.
최근에 UTF8 작업이 많았기에 오라클도 UTF8 구축해 PHP와 연동해 보고자 했다.
그런데 쉽지 않았다. 자료는 꽤 있었지만 UTF8 관련 자료는 리눅스 계열쪽이 많았다.
윈도우XP에서의 기본환경이 UTF8 이 아닌관계로 나름 고생이 많았다.

우선 오라클 캐릭터셋에 대한 개념을 잡기위해 아래의 문서를 참조하길 바란다.
http://www.oracle.com/technology/global/kr/pub/columns/oracle_nls_1.html

목적은 윈도우환경에서 아파치 PHP 오라클 연동해서 UTF8의 Web 환경을 구축하고자 하는것이다.
물론 오라클 역시도 UTF8을 기본으로 한다.
단 데이터 입력은 sqlplus 를 이용하고자 한다.
이는 우편번호 같은 sql문으로 처리되어 있는 데이터를 입력하기 위해서다.
toad 나 그외 툴로 sql 문을 처리하면 입력속도가 너무 느리며 시스템 부하가 너무 크기 때문이다.

1. 웹서버 및 PHP 환경설정
UTF8 관련 웹환경 구축에 관련 설명은 생략하겠다.
이부분을 설명하기에는 내용이 많고 환경이 다양하기 때문이다.


2. 오라클 데이터베이스 설정
sqlplus 나 그외 툴로 sys 로 로그인한후
select * from nls_database_parameters; 를 날려보자.

그중 NLS_CHARACTERSET 부분을 확인해 보면 현재의 데이터베이스 캐릭터 셋을 알수있다.
앞의 참조 문서를 봤으면 정상적인 한국어를 사용할수 있는 캐릭터셋은 4가지란걸 알수 있다.
KO16KSC5601, KO16MSWIN949, UTF8, AL32UTF8
물론 자신은 US7ASCII 으로 한글을 사용하신다는 분이 있을수도 이는 mysql 과 비교해보면
euckr 이나 utf8 을 사용해야 하는데 latin1 을 사용하는 분들과 같은 맥락이라 볼수 있다.

그중 AL32UTF8 로 설정해보자.
update sys.props$ set value$='AL32UTF8' where name='NLS_CHARACTERSET';
commit;
이제 관리도구 -> 서비스 에서 오라클 서버를 재시작하자.


3. 클라이언트 환경 설정
- regedit 를 실행
- HKEY_LOCAL_MACHINE -> SOFTWARE -> ORACLE 까지 온 후에 오른쪽 마우스를 클릭후
   새로만들기 -> 문자열값 선택
   NLS_LANG 입력후 다시 NLS_LANG 을 선택후 오른쪽 마우스 클릭후 수정
   그리고 값 데이터에 AMERICAN_AMERICA.AL32UTF8 를 입력한다.
   이제 모든 클라이언트 sqlplus, 웹등 모두 NLS_LANG 에 의해 영향을 받는다.





 

    여기서 NLS_LANG 의 의미는 클라이언트에서 접속하는 환경을 의미한다.
    즉 메세지를 영어로 사용하고 캐릭터셋은 KO16MSWIN949 를 사용한다는 의미이다.

    참고로 오라클 클라이언트를 이용한 접속이니 클라이언트 Key 밑에 추가해야 하는게 아닌가라고 생각한다면
    잘못된 생각이다. ORACLE 키 밑에 추가해야 한다. 이것때문에도 하루 이상을 소비했다는 ㅡㅡ;;


4. UTF8 데이터 입력
HR 에 zipcode 란 table 을 만들어 데이터를 입력해보겠다.
우편번호는 스쿨에 자료실에 있는 우편번호중 압축을 풀면 나오는 여러가지 화일중에
zipcode_oracle_t1.zip 를 이용하기로 하자.
oracle_scheme_t1.sql 을 editplus 같은 edit 프로그램으로 열어 table 스키마를 조금 변경하도록 하자
utf8 환경에서 한글은 3byte 를 차지하기 때문이다.
CREATE TABLE ZIPCODE
(
  SEQ      NUMBER(5),
  ZIPCODE  VARCHAR2(7 BYTE),
  SIDO     VARCHAR2(6 BYTE),
  GUGUN    VARCHAR2(22 BYTE),
  DONG     VARCHAR2(78 BYTE),
  BUNJI    VARCHAR2(25 BYTE)
);
변경후에는 utf8로 인코딩을 변경하여 D:\ 에 저장해보자.
ORACLE_T1.sql 도 열어서 인코딩을 utf8 로 변경하여 D:\ 저장하도록 하자.

만약 임시로 NLS_LANG의 값을 변경하고자 할때는 cmd 창을 실행 시킨후
set NLS_LANG=American_America.UTF8 를 실행한다.
그리고 sql 플러스에 접속하면 된다.
이는 NLS_LANG의 환경을 임시적으로 American_America.UTF8 로 만드는것이다.
그런데 Korean_Korea.UTF8 로 하지 않는거에 이상하게 생각할수 있다.
Korean_Korea.UTF8 로 하면 아래의 이미지와 같이 한글 메세지가 다 깨져 나와서 데이터가 제대로 들어간건지
아니면 오류가 난건지 분간할수가 없어서 그렇다.







 

이제 hr 유저로 로그인한후
sql> @D:\oracle_scheme_t1.sql
sql> commit;
sql> @D:\ORACLE_T1.sql
sql> commit;

이제 실제로 데이터가 잘들어 갔는지 웹에서 불러보자
아래의 소스에서 IP_ADDR , SID 및 패스워드 등을 수정한후 웹에서 불러보자

                            <?php
header("Content-Type: text/html; charset=utf-8");
$gDB ="(DESCRIPTION = ( ADDRESS =(PROTOCOL = TCP)(HOST = IP_ADDR)(PORT = 1521)) (CONNECT_DATA = (SID = ORCL)) )";
$gConn = oci_connect('HR', '패스워드', $gDB);

$sListScale = 20;
$sPageScale = 10;
$sStart = (!$_REQUEST[sStart]) ? 0 : $_REQUEST[sStart];


//=============================================================================
//  description    : 페이지 넘기기
//  param            : $fListScale 한화면에 뿌려질 List 갯수, $fPageScale 한화면에 뿌려질 페이지수,
//                         $fTotal 전체 List 갯수, $fStart 페이지의 첫 레코드 위치, $fPagingUrl 연결될 URL
//  return            : 페이징 Html
//=============================================================================
function getPaging($fListScale,$fPageScale,$fTotal,$fStart,$fPagingUrl) {
    $fPagingUrl = (!strstr($fPagingUrl,"?")) ? $fPagingUrl."?" : $fPagingUrl."&" ;
    if($fTotal > $fListScale) {
        $fPage =  floor($fStart/($fListScale*$fPageScale));

        $fReturn .= "
        <TABLE BORDER='0' WIDTH='' CELLPADDING='0' CELLSPACING='1'>
        <TR><TD ALIGN='center' class='f11_02'> ";

        $fPP=$fStart-$fListScale;
        $fNP=$fStart+$fListScale ;

        // 처음으로 이동
        if($fPP>=0) {
            $fReturn .= "
            <A HREF='$fPagingUrl"."sStart=0'>처음</A> ";
        }

        // Page 만큼 앞으로 이동
        if( $fStart+1 >  $fListScale*$fPageScale ) {
            $fPreStart = $fListScale*($fPage*$fPageScale - 1);
            $fReturn .= "
            <A HREF='$fPagingUrl"."sStart=$fPreStart'>이전</A>";
        }

        // Page Scale 만큼 출력
        for($i=0; $i < $fPageScale ; $i++) {
            $fLn = ($fPage * $fPageScale + $i)*$fListScale;
            $fVk= $fPage * $fPageScale + $i+1;
            if($fLn<$fTotal) {
                if($fLn!=$fStart) { $fReturn .= " <A HREF='$fPagingUrl"."sStart=$fLn'>[$fVk]</A> "; }
                else { $fReturn .= " <B>$fVk</B> "; }
            }
        }

        // PageScale 만큼 뒤로 이동
        if($fTotal > (($fPage+1)*$fListScale*$fPageScale)) {
            $fNstart=($fPage+1)*$fListScale*$fPageScale;
            $fReturn .= "
            <A HREF='$fPagingUrl"."sStart=$fNstart'>다음</A> ";
        }

        // 마지막 페이지
        if($fNP<$fTotal) {
            $fLast = (floor($fTotal/$fListScale))*$fListScale;
            $fReturn .= "
            <A HREF='$fPagingUrl"."sStart=$fLast'>마지막</A> ";
        }

        $fReturn .= "
        </TD></TR>
        </TABLE>";
    }
    return $fReturn;
}

$query = "select count(*) as cnt from HR.ZIPCODE $sCountWhere";
$stid = oci_parse($gConn, $query);
oci_execute($stid);
$sResult = oci_fetch_array($stid,OCI_ASSOC);
echo $sTotal = $sResult[CNT];

$query = "select * from (select ROW_NUMBER( ) OVER (ORDER BY seq) AS RNUM, zipcode.* from zipcode) A where A.RNUM>$sStart and A.RNUM<=$sStart+$sListScale";
$stid = oci_parse($gConn, $query);
oci_execute($stid);


$th = 0; // Table Header
echo "<table>\n\n";
while ($sResult = oci_fetch_array($stid, OCI_ASSOC)) {
    if (!$th) {
        $keys = (array_keys($sResult));
        echo "\n<tr>\n";
        foreach ($keys as $k) { echo "<th>" . $k . "</th>\n"; }
        echo "</tr>\n";
        $th = 1; // Table header done !
    }
    echo "\n<tr>\n";
    foreach ($keys as $k) {echo "<td>" . $sResult[$k] . "</td>\n";}
    echo "</tr>\n";
    $count = $count + 1;
}
echo "</table>\n\n";
echo "<h3>" . $count . " records</h3>";





oci_close($gConn);

echo getPaging($sListScale,$sPageScale,$sTotal,$sStart,"oracle.php");
?>

여기까지 정상적으로 나왔다면 UTF8 환경이 구축되었다고 할수 있다.

참고) 클라이언트 툴중 Toad 를 많이 사용하는데 Toad 는 9.x 이상부터 유니코드를 지원하는걸로 알고있다.
하위버젼의 Toad 에 글이 깨진다고 해서 잘못 들어간게 아니라는걸 확인했으면 좋겠다.
유니코드를 제대로 지원하는 툴로써 오라클에서 제공하는 SQL Developer 라는 툴이 있다.
무료 버젼이며 자바기반으로 돌아간다.
SQL Developer 는 오라클 mysql MSSQL Access, Sybase 등 여러 DB를 지원하지만 기능은 타 전용툴에
비해 약하다.
http://www.oracle.com/technology/products/database/sql_developer/index.html