새로 도입하는 시스템이 MS-SQL을 사용한다고 해서 기존에 사용하던 Oracle에서 일부 Data는 초기에 한번, 일부 Data는 주기적으로 동기화를 맞춰주는 작업을 해야합니다. 초기에 한번 이전해 주는 작업은 MS-SQL의 SSIS라는 기능을 이용해서 넘겨주기로 했고, 기능 테스트도 이미 했죠. 문제는 주기적으로 Data의 동기화를 맞춰주는 작업인데요. DB 복제 솔루션을 이용하거나 ETL을 이용하면 쉽게 해결되겠지만, 예산이 없어서 보류하고요. 다른 방법을 찾아보기로 결정했었죠. 그래서 알아본게 다음의 두가지입니다.

1. Oracle Gateway를 이용한 이기종 DBMS간 Data 공유
2. MS-SQL의 Open Query를 이용한 이기종 DBMS간 Data 공유


 Oracle DB에 원천 Data가 있으니 변경된 내용이 생길때 바로바로 적용하기 위해서는 Oracle Gateway를 이용하는게 좋을것 같긴 한데요. 문제는 이건 제가 한번도 해보질 않아서 프로젝트 일정에 맞출수가 없을 것 같더군요. 그래서 MS-SQL에서 구현하기로 했습니다. Open query는 예전에도 써본적이 있거든요.
자꾸 이러면 실력이 늘지 않을텐데 큰일입니다. ^^;  자~ 이제 MS-SQL의 Open query를 이용해서 주기적으로 Data 동기화를 맞춰주는 기능을 구현해보도록 하겠습니다.

 제일 먼저 할 일은 MS-SQL 서버에 Oracle client를 설치하는 일입니다. 설치가 완료되면 Data를 가져올 Oracle server의 정보를 tnsnames.ora에 설정해주면 됩니다. 이제 Linked server를 설정해줄 차례입니다.

 Open Query를 사용하기 위해서 우선 Oracle과 Link를 걸어야 합니다. SQL Server Management Studio에서 [연결된 서버]라는 항목에 추가를 해주면 됩니다. 이때 [Oracle provider for OLEDB]를 선택해서 사용하시는게 좋습니다. MS에서 제공하는 OLEDB provider를 사용할 수도 있는데, 이건 뭔가 문제가 있어보이더군요. Open query에서는 테스트해보지 않았지만, SSIS에서 Oracle의 Data를 가져올때 데이터형을 좀 잘못 가져오는것 같더군요. tnsnames.ora에 설정된 이름과 사용할 Oracle의 계정 정보 등을 입력해서 linked server를 생성하시면 됩니다.

 이제 Open query에 대해서 얘기해볼까합니다. Open query를 이용하면 MS-SQL에서 Oracle DB에 insert, select, update, delete를 실행 할 수 있습니다.

USE TESTDB
GO

SELECT * FROM OPENQUERY(LINK_NAME, `SELECT * FROM 테이블이름`);


UPDATE OPENQUERY(LINK_NAME, `SELECT A FROM 테이블이름 WHERE 조건1`)
SET A='AA' WHERE 조건2;

DELETE OPENQUERY(LINK_NAME, `SELECT A FROM 테이블이름 WHERE 조건1`)
 위의 query문을 보시면 update문을 실행시키는데 select문을 실행시키고 set을 해주는 부분이 보일겁니다. 그리고 조건이 2개 붙은 부분이 보일겁니다. [조건2]가 붙는 이유는 [조건1]에 ms-sql의 프로시져에서 사용하는 변수를 적용할 수 없기 때문입니다. 변수로 처리하지 않고 문자열로 넣어서 처리할 수 있는 부분은 [조건1]에 다 넣어주고, 변수로 받아서 넣어줘야할 내용은 [조건2]에 넣어주면 됩니다. 아래에 프로시져 코드를 보시면 바로 이해하실 겁니다.

이제 배치작업을 위해서 해당 기능을 프로시져로 만듭니다. 제가 작성한 간단한 샘플 코드를 보여드리겠습니다.

USE [testdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [tdb].[user_sync]
AS

    DECLARE ora_cursor CURSOR FOR
    SELECT TRG_FLAG, USER_ID, USER_NAME, TEL, CEL, EMAIL, ZIP_CD, ADDR1, ADDR2
       FROM OPENQUERY(VOCA2, 'SELECT B.TRG_FLAG, B.USER_ID, A.USER_NAME, A.TEL, A.CEL, 
                                                               A.EMAIL, A.ZIP_CD, A.ADDR1, A.ADDR2
                                                     FROM USER_TEST A, USER_TRG B
                                                    WHERE B.USER_ID = A.USER_ID(+)  AND B.MIG_DATE IS NULL');

    OPEN ora_cursor

    DECLARE @TRG_FLAG        VARCHAR(1)
    DECLARE @USER_ID            VARCHAR(30)
    DECLARE @USER_NAME            VARCHAR(50)
    DECLARE @TEL            VARCHAR(50)
    DECLARE @CEL            VARCHAR(50)
    DECLARE @EMAIL        VARCHAR(100)
    DECLARE @ZIP_CD            VARCHAR(7)
    DECLARE @ADDR1        VARCHAR(100)
    DECLARE @ADDR2        VARCHAR(100)

    FETCH NEXT FROM ora_cursor INTO @TRG_FLAG, @ USER_ID , @USER_NAME, @USER_TEL, @USER_CEL, @USER_EMAIL, @ZIP_CD, @USER_ADDR1, @USER_ADDR2

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF (@TRG_FLAG = 'I')
            BEGIN
                INSERT INTO USER_TEST  ( USER_ID , USER_NAME, USER_TEL, USER_CEL, USER_EMAIL, ZIP_CD, USER_ADDR1, USER_ADDR2)
                VALUES(@USER_ID, @USER_NAME, @USER_TEL, @USER_CEL, @USER_EMAIL, @ZIP_CD, @USER_ADDR1, @USER_ADDR2);

                UPDATE OPENQUERY(VOCA2, 'SELECT MIG_FLAG, MIG_DATE, USER_ID FROM  USER_TRG  WHERE TRG_FLAG=''I'' AND MIG_FLAG=''N''')
                    SET MIG_FLAG='Y', MIG_DATE=GETDATE()
                    WHERE USER_ID=@USER_ID;
            END;
        ELSE IF (@TRG_FLAG = 'U')
            BEGIN
                UPDATE  USER_TEST    SET USER_NAME=@USER_NAME, USER_TEL=@USER_TEL, USER_CEL=@USER_CEL, USER_EMAIL=@USER_EMAIL, ZIP_CD=@ZIP_CD,
                                           USER_ADDR1=@USER_ADDR1, USER_ADDR2=@USER_ADDR2
                WHERE USER_ID=@USER_ID;

                UPDATE OPENQUERY(VOCA2, 'SELECT MIG_FLAG, MIG_DATE, USER_ID FROM  USER_TRG   WHERE TRG_FLAG=''U'' AND MIG_FLAG=''N''')
                    SET MIG_FLAG='Y', MIG_DATE=GETDATE()
                    WHERE USER_ID=@USER_ID;
            END;
        ELSE IF (@TRG_FLAG = 'D')
            BEGIN
                DELETE FROM  USER_TEST    WHERE USER_ID=@USER_ID;

                UPDATE OPENQUERY(VOCA2, 'SELECT MIG_FLAG, MIG_DATE, USER_ID FROM  USER_TRG   WHERE TRG_FLAG=''D'' AND MIG_FLAG=''N''')
                    SET MIG_FLAG='Y', MIG_DATE=GETDATE()
                    WHERE USER_ID=@USER_ID;
            END;

        INSERT INTO dbo.USER_TEST_LOG(REG_DATE, USER_ID, TRG_FLAG) VALUES(GETDATE(), @USER_ID, @TRG_FLAG);
        
    FETCH NEXT FROM ora_cursor INTO @TRG_FLAG, @USER_ID, @USER_NAME, @USER_TEL, @USER_CEL, @USER_EMAIL, @ZIP_CD, @USER_ADDR1, @USER_ADDR2 
    END;

    CLOSE ora_cursor                                        -- 커서 클로즈

    DEALLOCATE ora_cursor                              -- 커서 메모리 반환
GO




자 이제 배치작업으로 주기적으로 실행시키는 일만 남았네요.


 Oracle DBMS를 사용하면서 수 많은 개발자들이 한번쯤은 접하게되는 문제가 "지금 운영중인 DB의 캐릭터셋 설정때문에 한자, 혹은 특정 한글 문자의 입력이 안되는게 당연합니다. 지금 캐릭터셋을 바꾸면 Data가 깨질수도 있어요."라는 DBA의 답변...이다.
 이런말 하기는 참 싫지만 내가 설치한 DB도 아니고... 새로 구축하는 DB면 이렇게 설치 안 하겠는데... 암튼...
(사실 이렇게 말해놓고는 지난번에 설치한 DB는 이 회사 왕고참 과장님의 의견(기존에 사용하던 DB와 캐릭터셋이 같아야 한다는...)에 따라서 KSC5601로 설치했다. 아~ 소신대로 살기 참 힘들죠~잉~)

OTN에 NLS관련 내용을 정리한 문서가 있어서 소개합니다. 언젠간 저도 이런 곳에 문서를 올릴 수 있는 능력자가 될 수 있기를...

보러가기
오라클과 NLS의 찰떡궁합 들여다보기(1)
오라클과 NLS의 찰떡궁합 들여다보기(2)
IBM DeveloperWorks 한글 사이트에 올라온 글 중에서 가상화 관련 문서 두개를 소개하려합니다.

원문 보러가기
1. VM 전개 자동화하기
2. Linux 하이퍼바이저 분석

 Linux에서의 가상화 솔루션과 VM 전개 자동화에 관한 글인데, 일단 DeveloperWorks 상의 분류는 Linux로 되어 있네요. [VM 전개 자동화하기]는 VMWare를 기준으로 설명을 하고 있고요. [Linux 하이퍼바이저 분석]은 오픈소스인 KVM(Kernel-based Virtual Machine)과 Lguest(이전에는 lhype)로 설명하고 있습니다.
 흠... 둘 다 써보진 않았지만 아주 흥미로운 내용이었습니다. 다만, 아직 Linux에서의 가상화 솔루션을 많이 경험해보지 않아서 인지 [VM 전개 자동화하기]문서 보다는 [Linux 하이퍼바이저 분석]가 좀더 재미있더군요. 소스 코드가 없어서 그런건지... ^^;

 Oracle RAC을 집에 있는 PC에 구현해보려하는데, OTN에서 찾은 문서에는 Oracle VM을 사용하더군요. Oracle VM이 Xen 기반인걸로 알고 있는데, Xen에 대한 설명은 없어서 좀 아쉽더군요. HDD랑, RAM이랑 증설한 뒤에 빨리 집에다가 구성해봐야 할텐데요...

아... 암튼... 이번에 소개하는 [VM 전개 자동화하기], [Linux 하이퍼바이저 분석] 모두 도움이 될 만한 내용이라고 생각합니다. 한번 보시길...
 드디어 Oracle database 11g의 Release 2가 홈페이지에서 다운로드 가능해졌습니다.
32비트, 64비트 버전의 리눅스용으로 나와있네요. 흠... 한번 설치해 볼까나...
오늘에야 알게된건데, Oracle database 11g에는 Warehouse builder가 내장되어 있다고 하네요.
음... 점점 모든 기능을 다 가지게 되네요.

다운로드 받으러 가기
 이번에 개발 장비의 Oracle DBMS를 9.2.0.4 버전에서 9.2.0.8로 패치했습니다. 패치 과정도 만만치 않았습니다. 패치후 Post patch 과정을 진행하는데, 운영하던 DB라서 그런건지, 일반 PC에 Linux를 설치해서 운영하는 서버라 성능이 좋지 않아서 인지, 예전에 IBM P 시리즈에서 패치하던때랑은 달리 시간이 많이 걸리더군요.
 암튼 이런 과정을 거친후에 문제가 발생했습니다. Pro*C로 서버 데몬을 개발하시던 분이 갑자기 오류가 발생한다고 하시더군요. 이런... 이제 문제 해결에 들어가야 겠죠.

 오류 메세지는 아래와 같았습니다.
PCC-02081: CMD-LINE: Unterminated option value list or value list was truncated.

 관련 문서를 찾아보니 아래와 같은 내용이 나왔습니다.
PCC-02081: CMD-LINE: Unterminated option value list or value list was truncated.
    Cause: An option that takes a list of values was entered. The value list did not have a closing parenthesis. This error may also occur if the list of values entered on a single line was too long and Pro*C truncated it.
    Action: Ensure that all value lists are terminated with a closing parenthesis. Split long value lists into individual entries.

내용인 즉슨... 옵션 값이 길어서 잘라서 읽어들였다... 뭐... 이런것 같네요. 그래서
/opt/oracle/product/9.2.0.4/precomp/admin/pcscfg.cfg 파일을 열어서는 지난번과는 달리 옵션으로 넘기는 데릭토리 이름중에서 현재 서버에는 존재하지 않는 디렉토리(예를 들어 CentOS인데 SUSE리눅스의 디렉토리 경로가 설정되어 있더군요.)들을 삭제해줬더니 컴파일 오류가 사라지더군요.
아... 겨우... 해결했네요. ^^

 Linux에 Oracle DBMS를 설치하고, Client를 설치하면서 Pro*C까지 설치를 했는데 막상 make 파일을 돌려보면 컴파일 오류가 발생하는 경우가 많죠. 저희 개발자분이 새로 설치한 개발 장비에서 설정이 안되어 있다고해서 거의 하루를 헤메다가 해결을 했습니다.
 저희 개발 장비의 문제는 기존에 설치된 GCC 버전이 Pro*C에 설정된 버전과 틀려서 헤더 파일들의 위치(디렉토리 이름)를 새로 설정해서 해결을 했습니다.

 [오라클 설치 위치/precomp/admin/pcscfg.cfg] 파일을 vi로 열어보면 아래와 같은 내용이 나옵니다.
[oracle@Test2 /opt/oracle/product/10g/precomp/admin]$ cat pcscfg.cfg
sys_include=(/ade_autofs/ade_linux/RDBMS_10.2.0.4.0_LINUX.rdd/080216/precomp/public,/usr/include,/usr/lib/gcc/i386-redhat-linux/4.1.1/include,/usr/lib/gcc/i386-redhat-linux/3.4.5/include,/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include,/usr/lib/gcc/i586-suse-linux/4.1.0/include)
ltype=short

 여기에 자신의 PC와 맞는 gcc-lib 관련 디렉토리가 설정되어 있는지 확인을 하고 없다면 추가해주면 됩니다.
 Oracle DBMS를 운영하다보면 전임자의 실수이거나, 게으른 본인의 생각없는 설치 및 운영으로 인해서 디스크 공간의 부족함으로 인해서 서비스가 중단되는 일이 생기기도 합니다. 본사 내에서 마구잡이로 사용하는 개발용 DB중에 그런 장비가 있었는데 /opt/oracle 디렉토리가 사용율 100%에 이르러서야 확인을 하게 되었습니다.
 문제는 현재 각종 로그가 쌓이는 디렉토리와 $ORACLE_HOME, 그리고 각종 시스템 관련 Datafile, redo log file 등이 같은 파티션에 저장이 되고 있더군요. 그래서 ... 서비스를 중지시키지 않고 작업을 해야겠다는 생각에 redo log file을 옮기기로 결정했습니다. 이게 제일 만만해보이더군요.

리두로그 그룹 및 파일 현황 확인
SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#;

    GROUP# STATUS           TYPE      MEMBER
---------- ---------------- ------- ----------------------------------------
         1 CURRENT          ONLINE  /opt/oracle/oradata/edo01.log                                    
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log            
         3 INACTIVE         ONLINE  /opt/oracle/oradata/redo03.log 

네번째 리두로그 그룹 및 파일 추가

SQL> alter database add logfile group 4('/data/orasys/redo04.log') size 100M;

Database altered.

SQL>

리두로그 그룹 및 파일 추가 결과 확인
SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#;

    GROUP# STATUS           TYPE    MEMBER                                                                              
---------- ---------------- ------- ---------------------------------------- 
         1 CURRENT          ONLINE  /opt/oracle/oradata/redo01.log
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log           
         3 INACTIVE         ONLINE  /opt/oracle/oradata/redo03.log             
         4 UNUSED           ONLINE  /data/orasys/redo04.log

기존 리두로그 파일 그룹중 하나 삭제
SQL> alter database drop logfile group 3;
SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#(+);

    GROUP# STATUS           TYPE    MEMBER
---------- ---------------- ------- ----------------------------------------   
         1 CURRENT          ONLINE  /opt/oracle/oradata/redo01.log
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log            
         4 UNUSED           ONLINE  /data/orasys/redo04.log

리두로그 파일 그룹 3을 새로운 위치에 추가
SQL> alter  database add logfile group 3 ('/data/orasys/redo03.log') SIZE 100M;

Database altered.

리두로그 파일 그룹 3이 정상적으로 추가되었는지 확인
SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#(+);

    GROUP# STATUS           TYPE    MEMBER
---------- ---------------- ------- ----------------------------------------   
         1 CURRENT          ONLINE  /opt/oracle/oradata/redo01.log
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log            
         3 UNUSED           ONLINE  /data/orasys/redo03.log                    
         4 UNUSED           ONLINE  /data/orasys/redo04.log                             

SQL>

로그 스위치를 강재로 일으키며 상태값을 확인해본다.
SQL> alter system switch logfile;

System altered.

SQL>
SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#(+);

    GROUP# STATUS           TYPE    MEMBER
---------- ---------------- ------- ----------------------------------------    
         1 ACTIVE           ONLINE  /opt/oracle/oradata/redo01.log
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log              
         3 CURRENT          ONLINE  /data/orasys/redo03.log                    
         4 UNUSED           ONLINE  /data/orasys/redo04.log                            

SQL>
SQL>  alter system switch logfile;

System altered.

SQL> select a.group#, a.status, b.type, b.member from v$log a, v$logfile b where a.group#=b.group#(+);

    GROUP# STATUS           TYPE    MEMBER
---------- ---------------- ------- ----------------------------------------    
         1 INACTIVE         ONLINE  /opt/oracle/oradata/redo01.log
         2 INACTIVE         ONLINE  /opt/oracle/oradata/redo02.log             
         3 INACTIVE         ONLINE  /data/orasys/redo03.log
         4 CURRENT          ONLINE  /data/orasys/redo04.log

SQL>


Oracle을 이용하면서 자주 사용하는 기능 중의 하나인 TO_CAHR을 이용해서 원하는 형태의 날짜 정보를 보여주는 방법에 대해서 정리해봅니다.

TO_CHAR(날짜, '표현방식'[, 'NLS정보'])

SELECT
       TO_CHAR(SYSDATE, 'YYYY.MM.DD') D_YYYYMMDD,
       TO_CHAR(SYSDATE, 'Y','NLS_DATE_LANGUAGE=KOREAN') D_Y,
       TO_CHAR(SYSDATE, 'YEAR','NLS_DATE_LANGUAGE=KOREAN') D_YEAR,
       TO_CHAR(SYSDATE, 'Year','NLS_DATE_LANGUAGE=KOREAN') D_YEAR_1,
       TO_CHAR(SYSDATE, 'MON') D_MON,
       TO_CHAR(SYSDATE, 'Mon') D_MON_1,
       TO_CHAR(SYSDATE, 'MONTH') D_MONTH,
       TO_CHAR(SYSDATE, 'Month') D_MONTH_1,
       TO_CHAR(SYSDATE, 'D') D_D,
       TO_CHAR(SYSDATE, 'DD') D_DD,
       TO_CHAR(SYSDATE, 'DDD') D_DDD,
       TO_CHAR(SYSDATE, 'DAY') D_DAY,
       TO_CHAR(SYSDATE, 'Day') D_DAY_1,
       TO_CHAR(SYSDATE, 'DY','NLS_DATE_LANGUAGE=KOREAN') D_DY,
       TO_CHAR(SYSDATE, 'Dy') D_DY_1
  FROM DUAL
 UNION ALL
SELECT
       TO_CHAR(SYSDATE, 'YYYY.MM.DD','NLS_DATE_LANGUAGE=AMERICAN') D_YYYYMMDD,
       TO_CHAR(SYSDATE, 'Y','NLS_DATE_LANGUAGE=AMERICAN') D_Y,
       TO_CHAR(SYSDATE, 'YEAR','NLS_DATE_LANGUAGE=AMERICAN') D_YEAR,
       TO_CHAR(SYSDATE, 'Year','NLS_DATE_LANGUAGE=AMERICAN') D_YEAR_1,
       TO_CHAR(SYSDATE, 'MON','NLS_DATE_LANGUAGE=AMERICAN') D_MON,
       TO_CHAR(SYSDATE, 'Mon','NLS_DATE_LANGUAGE=AMERICAN') D_MON_1,
       TO_CHAR(SYSDATE, 'MONTH','NLS_DATE_LANGUAGE=AMERICAN') D_MONTH,
       TO_CHAR(SYSDATE, 'Month','NLS_DATE_LANGUAGE=AMERICAN') D_MONTH_1,
       TO_CHAR(SYSDATE, 'D','NLS_DATE_LANGUAGE=AMERICAN') D_D,
       TO_CHAR(SYSDATE, 'DD','NLS_DATE_LANGUAGE=AMERICAN') D_DD,
       TO_CHAR(SYSDATE, 'DDD','NLS_DATE_LANGUAGE=AMERICAN') D_DDD,
       TO_CHAR(SYSDATE, 'DAY','NLS_DATE_LANGUAGE=AMERICAN') D_DAY,
       TO_CHAR(SYSDATE, 'Day','NLS_DATE_LANGUAGE=AMERICAN') D_DAY_1,
       TO_CHAR(SYSDATE, 'DY','NLS_DATE_LANGUAGE=AMERICAN') ADA,
       TO_CHAR(SYSDATE, 'Dy','NLS_DATE_LANGUAGE=AMERICAN') ADA
  FROM DUAL;

 실행해보시면 재미난 결과가 나옵니다.
NLS_DATE_LANGUAGE를 AMERICAN으로 해주면 대소문자를 가려서 나오네요.
아래가 결과값입니다.

1 : 2009.06.10    9    TWO THOUSAND NINE    Two Thousand Nine    6월     6월     6월     6월     4    10    161    수요일    수요일    수    수
2: 2009.06.10    9    TWO THOUSAND NINE    Two Thousand Nine    JUN    Jun    JUNE         June         4    10    161    WEDNESDAY    Wednesday    WED    Wed


 이곳저곳 돌아다니다가 알게된 링크들입니다.

AIX 5L에 Oracle 설치 문서 : http://download.oracle.com/docs/cd/B19306_01/install.102/b19075/toc.htm

일본어판 Oracle 10g 문서를 네이버 번역기로 번역한 문서 링크 : http://j2k.naver.com/j2k_frame.php/korean/otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/index.htm

Oracle RAC관련 Oracle Magazine 문서 : Oracle RAC, 메인스트림 제품으로 업그레이드

Oracle wait event 모니터링 : http://www.oracle.com/technology/global/kr/pub/columns/dbtuning02.html

OTN Blogs & Opinion, 칼럼 : http://www.oracle.com/technology/global/kr/community/opinion/index.html
 OracleBase라는 웹 사이트에 올라와있는 Oracle 9i Streams 구현 관련 문서입니다.
요즘 10g와 9i 사이에 Oracle Streams로 Data 공유하는 기능을 구현하는 중이라서 이곳 저곳 뒤지고 있는 중입니다.

원문 : ORACLE-BASE - Oracle9i Streams

 영문으로 되어있다는 점만 빼면 좋습니다. ^^;
9i랑 10g랑은 서로 좀 틀려서 그런지 설정하는게 만만치 않군요.

+ Recent posts