2009년 7월 21일 화요일

Oracle Package - Update Cascade

Oracle에서는 MS-SQL과 달리, UPDATE CASCADE를 지원하지 않는다.

그러므로 이를 Trigger나 Package등으로 설정을 하여야 하는데

이를 간단하게 사용할 수 있는 Package가 있다.

 

 

PL/SQL로 다음의 Package를 생성한다.

 

CREATE OR REPLACE PACKAGE UPDATE_CASCADE
AS

    PROCEDURE ON_TABLE( P_TABLE_NAME      IN VARCHAR2,
                        P_PRESERVE_ROWID  IN BOOLEAN DEFAULT TRUE,
                        P_USE_DBMS_OUTPUT IN BOOLEAN DEFAULT FALSE );

END UPDATE_CASCADE;
/

CREATE OR REPLACE PACKAGE BODY UPDATE_CASCADE
AS

TYPE CNAMEARRAY IS TABLE OF USER_CONS_COLUMNS.COLUMN_NAME%TYPE
                   INDEX BY BINARY_INTEGER;

SQL_STMT           VARCHAR2(32000);
USE_DBMS_OUTPUT    BOOLEAN DEFAULT FALSE;
PRESERVE_ROWID     BOOLEAN DEFAULT TRUE;

FUNCTION Q( S IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
    RETURN '"'||S||'"';
END Q;

FUNCTION PKG_NAME( S IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
    RETURN Q( 'U' || S || 'P' );
END PKG_NAME;


FUNCTION VIEW_NAME( S IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
    RETURN Q( 'U' || S || 'V' );
END VIEW_NAME;

FUNCTION TRIGGER_NAME( S IN VARCHAR2, S2 IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
    RETURN Q( 'U' || S || S2 );
END TRIGGER_NAME;


FUNCTION STRIP( S IN VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
    RETURN LTRIM(RTRIM(S));
END STRIP;

PROCEDURE ADD( S IN VARCHAR2 )
IS
BEGIN
    IF ( USE_DBMS_OUTPUT ) THEN
        DBMS_OUTPUT.PUT_LINE( CHR(9) || S );
    ELSE
        SQL_STMT := SQL_STMT || CHR(10) || S;
    END IF;
END ADD;

 

PROCEDURE EXECUTE_IMMEDIATE
AS
    EXEC_CURSOR     INTEGER DEFAULT DBMS_SQL.OPEN_CURSOR;
    ROWS_PROCESSED  NUMBER  DEFAULT 0;
BEGIN
    IF ( USE_DBMS_OUTPUT ) THEN
        DBMS_OUTPUT.PUT_LINE( '/' );
    ELSE
        DBMS_SQL.PARSE(EXEC_CURSOR, SQL_STMT, DBMS_SQL.NATIVE );
        ROWS_PROCESSED := DBMS_SQL.EXECUTE(EXEC_CURSOR);
        DBMS_SQL.CLOSE_CURSOR( EXEC_CURSOR );
        DBMS_OUTPUT.PUT_LINE(
        SUBSTR( SQL_STMT, 2, INSTR( SQL_STMT,CHR(10),2)-2 ) );
        SQL_STMT := NULL;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
      IF DBMS_SQL.IS_OPEN(EXEC_CURSOR) THEN
        DBMS_SQL.CLOSE_CURSOR(EXEC_CURSOR);
      END IF;
      RAISE;
END;

PROCEDURE GET_PKEY_NAMES
( P_TABLE_NAME      IN OUT USER_CONSTRAINTS.TABLE_NAME%TYPE,
  P_PKEY_NAMES         OUT CNAMEARRAY,
  P_CONSTRAINT_NAME IN OUT USER_CONSTRAINTS.CONSTRAINT_NAME%TYPE )
IS
BEGIN
    SELECT TABLE_NAME, CONSTRAINT_NAME
      INTO P_TABLE_NAME, P_CONSTRAINT_NAME
      FROM USER_CONSTRAINTS
     WHERE ( TABLE_NAME = P_TABLE_NAME
             OR TABLE_NAME = UPPER(P_TABLE_NAME) )
            AND CONSTRAINT_TYPE = 'P' ;

    FOR X IN ( SELECT COLUMN_NAME , POSITION
                 FROM USER_CONS_COLUMNS
                WHERE CONSTRAINT_NAME = P_CONSTRAINT_NAME
                ORDER BY POSITION ) LOOP
        P_PKEY_NAMES( X.POSITION ) := X.COLUMN_NAME;
    END LOOP;
END GET_PKEY_NAMES;


PROCEDURE WRITE_SPEC( P_TABLE_NAME IN USER_CONSTRAINTS.TABLE_NAME%TYPE,
                      P_PKEY_NAMES IN CNAMEARRAY )
IS
    L_COMMA     CHAR(1) DEFAULT ' ';
BEGIN
    ADD( 'CREATE OR REPLACE PACKAGE ' || PKG_NAME(P_TABLE_NAME) );
    ADD( 'AS' );
    ADD( '--' );
    ADD( '    ROWCNT    NUMBER DEFAULT 0;' );
    ADD( '    INTRIGGER BOOLEAN DEFAULT FALSE;' );
    ADD( '--' );

    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '    TYPE C' || STRIP(I) || '_TYPE IS TABLE OF ' ||
                    Q(P_TABLE_NAME) || '.' || Q(P_PKEY_NAMES(I)) ||
                 '%TYPE INDEX BY BINARY_INTEGER;' );
            ADD( '--' );
            ADD( '    EMPTY_C' || STRIP(I) || ' C' || STRIP(I) || '_TYPE;' );
            ADD( '    OLD_C' || STRIP(I) || '   C' || STRIP(I) || '_TYPE;' );
            ADD( '    NEW_C' || STRIP(I) || '   C' || STRIP(I) || '_TYPE;' );
            ADD( '--' );
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;

    ADD( '--' );
    ADD( '    PROCEDURE RESET;' );
    ADD( '--' );
    ADD( '    PROCEDURE DO_CASCADE;' );
    ADD( '--' );

    ADD( '    PROCEDURE ADD_ENTRY' );
    ADD( '    ( ' );
    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '        ' || L_COMMA || 'P_OLD_C' || STRIP(I) || ' IN ' ||
                  Q(P_TABLE_NAME) || '.' || Q(P_PKEY_NAMES(I)) || '%TYPE ' );
            L_COMMA := ',';
            ADD( '        ,P_NEW_C' || STRIP(I) || ' IN OUT ' ||
                  Q(P_TABLE_NAME) || '.' || Q(P_PKEY_NAMES(I)) || '%TYPE ' );
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( '     );' );
    ADD( '--' );
    ADD( 'END ' || PKG_NAME(P_TABLE_NAME) || ';' );

END WRITE_SPEC;


PROCEDURE WRITE_BODY
( P_TABLE_NAME         IN USER_CONSTRAINTS.TABLE_NAME%TYPE,
  P_PKEY_NAMES      IN CNAMEARRAY,
  P_CONSTRAINT_NAME    IN USER_CONSTRAINTS.CONSTRAINT_NAME%TYPE )
IS
    L_COL_CNT         NUMBER DEFAULT 0;
    L_COMMA         CHAR(1) DEFAULT ' ';
    L_PKEY_STR      VARCHAR2(2000);
    L_PKEY_NAME_STR VARCHAR2(2000);
    L_OTHER_COL_STR VARCHAR2(2000);
BEGIN
    ADD( 'CREATE OR REPLACE PACKAGE BODY ' || PKG_NAME(P_TABLE_NAME) );
    ADD( 'AS' );
    ADD( '--' );

    ADD( '    PROCEDURE RESET ' );
    ADD( '    IS' );
    ADD( '    BEGIN' );
    ADD( '--' );
    ADD( '        IF ( INTRIGGER ) THEN RETURN; END IF;' );
    ADD( '--' );
    ADD( '        ROWCNT := 0;' );
    FOR I IN 1 .. 16 LOOP
        BEGIN
           IF (P_PKEY_NAMES(I) = P_PKEY_NAMES(I)) THEN
              L_COL_CNT := L_COL_CNT+1;
           END IF;
           ADD( '        OLD_C' || STRIP(I) || ' := EMPTY_C' || STRIP(I) || ';' );
           ADD( '        NEW_C' || STRIP(I) || ' := EMPTY_C' || STRIP(I) || ';' );
        EXCEPTION
           WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( '    END RESET;' );
    ADD( '--' );

    ADD( '    PROCEDURE ADD_ENTRY ' );
    ADD( '    ( ' );
    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '        ' || L_COMMA || 'P_OLD_C' || STRIP(I) || ' IN ' ||
                Q(P_TABLE_NAME) || '.' || Q(P_PKEY_NAMES(I)) || '%TYPE ' );
            L_COMMA := ',';
            ADD( '        ,P_NEW_C' || STRIP(I) || ' IN OUT ' ||
                  Q(P_TABLE_NAME) || '.' || Q(P_PKEY_NAMES(I)) || '%TYPE ' );
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( '     )' );
    ADD( '    IS' );
    ADD( '    BEGIN' );
    ADD( '--' );
    ADD( '        IF ( INTRIGGER ) THEN RETURN; END IF;' );
    ADD( '--' );
    ADD( '        IF ( ' );
    FOR I IN 1 .. L_COL_CNT LOOP
        IF ( I <> 1 ) THEN
            ADD( '            OR' );
        END IF;
        ADD( '             P_OLD_C' || STRIP(I) || ' <> ' ||
             'P_NEW_C' || STRIP(I) );
    END LOOP;
    ADD( '         ) THEN ' );
    ADD( '        ROWCNT := ROWCNT + 1;' );

    FOR I IN 1 .. L_COL_CNT LOOP
        ADD( '        OLD_C' || STRIP(I) ||
             '( ROWCNT ) := P_OLD_C' || STRIP(I) || ';' );
        ADD( '        NEW_C' || STRIP(I) ||
             '( ROWCNT ) := P_NEW_C' || STRIP(I) || ';' );
        ADD( '        P_NEW_C' || STRIP(I) ||
             ' := P_OLD_C' || STRIP(I) || ';' );
    END LOOP;

    ADD( '        END IF;' );
    ADD( '    END ADD_ENTRY;' );


    ADD( '--' );

    L_COMMA := ' ';
    FOR I IN 1 .. L_COL_CNT LOOP
        L_PKEY_STR      := L_PKEY_STR||L_COMMA||'$$_C' || STRIP(I) || '(I)';
        L_PKEY_NAME_STR := L_PKEY_NAME_STR || L_COMMA || Q(P_PKEY_NAMES(I));
        L_COMMA := ',';
    END LOOP;

    FOR X IN ( SELECT COLUMN_NAME
                 FROM USER_TAB_COLUMNS
                WHERE TABLE_NAME = P_TABLE_NAME
                  AND COLUMN_NAME NOT IN
                    ( SELECT COLUMN_NAME
                        FROM USER_CONS_COLUMNS
                       WHERE CONSTRAINT_NAME = P_CONSTRAINT_NAME )
                ORDER BY COLUMN_ID )
    LOOP
        L_OTHER_COL_STR := L_OTHER_COL_STR || ',' || Q(X.COLUMN_NAME);
    END LOOP;

    ADD( '    PROCEDURE DO_CASCADE' );
    ADD( '    IS' );
    ADD( '    BEGIN' );
    ADD( '--' );
    ADD( '        IF ( INTRIGGER ) THEN RETURN; END IF;' );
    ADD( '        INTRIGGER := TRUE;' );
    ADD( '--' );
    ADD( '        FOR I IN 1 .. ROWCNT LOOP' );
    ADD( '            INSERT INTO ' || P_TABLE_NAME || ' ( ' );
    ADD( '            ' || L_PKEY_NAME_STR );
    ADD( '            ' || L_OTHER_COL_STR || ') SELECT ');
    ADD( '            ' || REPLACE( L_PKEY_STR, '$$', 'NEW' ) );
    ADD( '            ' || L_OTHER_COL_STR );

    ADD( '            FROM ' || Q(P_TABLE_NAME) || ' A' );
    ADD( '            WHERE (' || L_PKEY_NAME_STR || ' ) = ' );
    ADD( '                  ( SELECT ' || REPLACE(L_PKEY_STR,'$$','OLD') );
    ADD( '                      FROM DUAL );' );
    ADD( '--' );
    IF ( PRESERVE_ROWID ) THEN
       ADD( '            UPDATE ' || Q(P_TABLE_NAME) || ' SET ' );
       ADD( '            ( ' || L_PKEY_NAME_STR || ' ) = ' );
       ADD( '            ( SELECT ' );
       FOR I IN 1 .. L_COL_CNT LOOP
          IF ( I <> 1 ) THEN ADD( '                  ,' ); END IF;
          ADD( '                 DECODE( ' || Q(P_PKEY_NAMES(I)) ||
          REPLACE(', OLD_C$$(I), NEW_C$$(I), OLD_C$$(I) )', '$$',STRIP(I)) );
       END LOOP;
       ADD( '              FROM DUAL )' );
       ADD( '            WHERE ( ' || L_PKEY_NAME_STR || ' ) =' );
       ADD( '                  ( SELECT ' || REPLACE(L_PKEY_STR,'$$','NEW') );
       ADD( '                      FROM DUAL )' );
       ADD( '               OR ( ' || L_PKEY_NAME_STR || ' ) =' );
       ADD( '                  ( SELECT ' || REPLACE(L_PKEY_STR,'$$','OLD') );
       ADD( '                      FROM DUAL );' );
    END IF;

    FOR X IN ( SELECT TABLE_NAME, CONSTRAINT_NAME
                 FROM USER_CONSTRAINTS
                WHERE R_CONSTRAINT_NAME = P_CONSTRAINT_NAME
                  AND CONSTRAINT_TYPE = 'R' ) LOOP

        L_COMMA := ' ';
        L_OTHER_COL_STR := '';
        FOR Y IN ( SELECT COLUMN_NAME
                     FROM USER_CONS_COLUMNS
                    WHERE CONSTRAINT_NAME = X.CONSTRAINT_NAME
                    ORDER BY POSITION ) LOOP
            L_OTHER_COL_STR := L_OTHER_COL_STR || L_COMMA || Q(Y.COLUMN_NAME);
            L_COMMA := ',';
        END LOOP;

        ADD( '--' );
        ADD( '            UPDATE ' || Q( X.TABLE_NAME ) || ' SET ');
        ADD( '            ( ' || L_OTHER_COL_STR || ' ) = ' );
        ADD( '            ( SELECT  ' || REPLACE( L_PKEY_STR, '$$', 'NEW' ) );
        ADD( '                FROM DUAL )' );
        ADD( '            WHERE ( ' || L_OTHER_COL_STR || ' ) = ' );
        ADD( '                  ( SELECT  ' ||
                                REPLACE( L_PKEY_STR, '$$', 'OLD' ) );
        ADD( '                    FROM DUAL );' );

    END LOOP;

    ADD( '--' );
    ADD( '            DELETE FROM ' || Q(P_TABLE_NAME)  );
    ADD( '             WHERE ( ' || L_PKEY_NAME_STR || ' ) = ' );
    ADD( '                   ( SELECT ' ||
    REPLACE( L_PKEY_STR, '$$', 'OLD' ) );
    ADD( '                       FROM DUAL);' );
    ADD( '        END LOOP;' );

    ADD( '--' );
    ADD( '        INTRIGGER := FALSE;' );
    ADD( '        RESET;' );
    ADD( '   EXCEPTION' );
    ADD( '       WHEN OTHERS THEN' );
    ADD( '          INTRIGGER := FALSE;' );
    ADD( '          RESET;' );
    ADD( '          RAISE;' );
    ADD( '    END DO_CASCADE;' );
    ADD( '--' );
    ADD( 'END ' || PKG_NAME( P_TABLE_NAME ) || ';' );

END WRITE_BODY;


PROCEDURE WRITE_BU_TRIGGER( P_TABLE_NAME IN USER_CONSTRAINTS.TABLE_NAME%TYPE,
                            P_PKEY_NAMES IN CNAMEARRAY )
IS
    L_COMMA CHAR(1) DEFAULT ' ';
BEGIN
    ADD( 'CREATE OR REPLACE TRIGGER ' || TRIGGER_NAME( P_TABLE_NAME, '1' ) );
    ADD( 'BEFORE UPDATE OF ' );
    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '   ' || L_COMMA || Q(P_PKEY_NAMES(I)) );
            L_COMMA := ',';
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( 'ON ' || Q(P_TABLE_NAME) );
    ADD( 'BEGIN ' || PKG_NAME(P_TABLE_NAME) || '.RESET; END;' );
END WRITE_BU_TRIGGER;


PROCEDURE WRITE_BUFER_TRIGGER
( P_TABLE_NAME IN USER_CONSTRAINTS.TABLE_NAME%TYPE,
  P_PKEY_NAMES IN CNAMEARRAY )
IS
    L_COMMA   CHAR(1) DEFAULT ' ';
BEGIN
    ADD( 'CREATE OR REPLACE TRIGGER '||TRIGGER_NAME( P_TABLE_NAME, '2' ) );
    ADD( 'BEFORE UPDATE OF ' );

    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '   ' || L_COMMA || Q(P_PKEY_NAMES(I)) );
            L_COMMA := ',';
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( 'ON ' || Q(P_TABLE_NAME) );
    ADD( 'FOR EACH ROW' );
    ADD( 'BEGIN ' );
    ADD( '   ' || PKG_NAME(P_TABLE_NAME) || '.ADD_ENTRY(' );

    L_COMMA := ' ';
    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '      ' || L_COMMA || ':OLD.' || Q(P_PKEY_NAMES(I)) );
            ADD( '      ,:NEW.' || Q(P_PKEY_NAMES(I)) );
            L_COMMA := ',';
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( '      );' );
    ADD( 'END;' );
END WRITE_BUFER_TRIGGER;

PROCEDURE WRITE_AU_TRIGGER( P_TABLE_NAME IN USER_CONSTRAINTS.TABLE_NAME%TYPE,
                            P_PKEY_NAMES IN CNAMEARRAY )
IS
    L_COMMA  CHAR(1) DEFAULT ' ';
BEGIN
    ADD( 'CREATE OR REPLACE TRIGGER ' || TRIGGER_NAME( P_TABLE_NAME, '3' ) );
    ADD( 'AFTER UPDATE OF ' );
    FOR I IN 1 .. 16 LOOP
        BEGIN
            ADD( '   ' || L_COMMA || Q(P_PKEY_NAMES(I)) );
            L_COMMA := ',';
        EXCEPTION
            WHEN NO_DATA_FOUND THEN EXIT;
        END;
    END LOOP;
    ADD( 'ON ' || Q(P_TABLE_NAME) );
    ADD( 'BEGIN ' || PKG_NAME(P_TABLE_NAME) || '.DO_CASCADE; END;' );
END WRITE_AU_TRIGGER;

PROCEDURE ON_TABLE( P_TABLE_NAME      IN VARCHAR2,
                    P_PRESERVE_ROWID  IN BOOLEAN DEFAULT TRUE,
                    P_USE_DBMS_OUTPUT IN BOOLEAN DEFAULT FALSE )
IS
    L_TABLE_NAME         USER_CONSTRAINTS.TABLE_NAME%TYPE DEFAULT P_TABLE_NAME;
    L_CONSTRAINT_NAME   USER_CONSTRAINTS.CONSTRAINT_NAME%TYPE;
    L_PKEY_NAMES        CNAMEARRAY;
    L_COMMA                CHAR(1) DEFAULT ' ';
BEGIN
    USE_DBMS_OUTPUT := P_USE_DBMS_OUTPUT;
    PRESERVE_ROWID  := P_PRESERVE_ROWID;

    GET_PKEY_NAMES( L_TABLE_NAME, L_PKEY_NAMES, L_CONSTRAINT_NAME );

    SQL_STMT := NULL;
    WRITE_SPEC( L_TABLE_NAME, L_PKEY_NAMES );
    EXECUTE_IMMEDIATE;
    WRITE_BODY( L_TABLE_NAME, L_PKEY_NAMES, L_CONSTRAINT_NAME );
    EXECUTE_IMMEDIATE;
    WRITE_BU_TRIGGER( L_TABLE_NAME, L_PKEY_NAMES );
    EXECUTE_IMMEDIATE;
    WRITE_BUFER_TRIGGER( L_TABLE_NAME, L_PKEY_NAMES );
    EXECUTE_IMMEDIATE;
    WRITE_AU_TRIGGER( L_TABLE_NAME, L_PKEY_NAMES );
    EXECUTE_IMMEDIATE;


END ON_TABLE;

END UPDATE_CASCADE;
/

 

SQL상에서 UPDATE CASCADE할 Table명을 포함하여 실행하면 끝!

만일, TBL_MEMBER의 PK를 참조하는 다른 FK들에 대하여 UPDATE CASCADE를 한다면,

EXEC UPDATE_CASCADE.ON_TABLE('TBL_MEMBER');

라고 입력하면 된다.

이 Package 외에도 여러방법이 있으므로, 참조해 보도록 한다.

출처는 http://asktom.oracle.com/tkyte/update_cascade/

펼쳐두기..


 

Oracle TableAdapter Query 생성 (With Parameter)

VS.Net에서 Oracle을 연결하는 방법은 여러가지 있지만,

간편하게 바인딩까지 해주는 마법사(데이터 >> 데이터 소스 추가)를 주로 이용힌다.

 

이렇게 추가된 데이터베이스는 Xml로 DataSet 설정되여 사용이 편리하며,

속성에 Data Source가 있다면, 단순클릭 몇번으로 쉽게 연결 할 수 있다.

 

또한 매개 변수 컬렉션 편집기를 통하여 추가적인 쿼리등도 수정할 수 있다.

 

이때 Parameter의 입력하는 방식이 연결에 사용한 방법에 따라 여러가지 방식으로 나뉜다.

별거 아닌 것 같지만, 이거 찾느라 하루종일 걸렸다. 제길...

MSDN에서의 단순 검색은 기본적인 해당사항(MS-SQL)에 대한 설명만 있어서

그외의 것에 대한 간단한 예문을 첨부한다.

 

SqlDataAdapter 개체를 사용하는 경우에는 문이 명명된 매개 변수를 사용한다.
Select * From Customers Where City = @City

 

OleDbDataAdapter 개체를 사용하는 경우에는 문이 물음표를 자리 표시자로 사용한다. Select * From Customers Where City = ?

 

OracleDataAdapter 개체를 사용하는 경우 Oracle 명명 매개 변수를 사용하는 문은 다음과 같다.
SELECT * FROM Customers WHERE CustomerID = :pCustomerID

 

Oracle의 경우, SQL 문이나 저장 프로시저에서 명명된 매개 변수를 사용할 때는 매개 변수 이름 앞에 콜론(:)을 붙여야 한다. 그러나 예를 들어, 코드에서 Add 메서드를 호출할 때처럼 명명된 매개 변수를 참조할 때는 명명된 매개 변수 앞에 콜론(:)을 붙이면 안된다. 데이터 공급자에서 콜론을 자동으로 제공한다.

2009년 7월 20일 월요일

Oracle instant client 설치

오라클이 설치되어 있지 않은 컴퓨터에서 작업을 하려면

 

기본적으로 클라이언트를 별도로 설치하여야 한다.

 

근데, 일반적인 - exe등을 이용한 - 설치가 아니라 조금 짜증이 나긴한다.;

 

우선 첨부된 파일을 받는다.

 

이는 현재 필자가 사용하는 Oracle 10.2를 기준으로 한 클라이언트 파일이며,

 

최신 및 사용 버전에 따른 파일은 http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/winsoft.html

에서 받으면 된다.

 

우선 다운 받은 파일을 압축 풀어 다음의 장소에 복사하도록 한다. 기본 디렉토리가 없을 경우 사용자가 직접 생성하면 된다.

C:\instantclient_10_2
C:\instantclient_10_2\network

network디렉토리의 경우 tnsnames.ora파일을 별도 관리하기 위함일 뿐 필수는 아니다.

그리고 해당 서버에 대한 tnsnames.ora 파일을 C:\instantclient_10_2\network 디렉토리에 복사한다.

 

시스템의 환경변수에 다음을 추가하도록 한다.

 - PATH : C:\instantclient_10_2

 - ORACLE_HOME : C:\instantclient_10_2

 - TNS_ADMIN = C:\instantclient_10_2\network

 

그리고 레지스트리를 수정한다.

실행 - regedit 입력

 

HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE
ORACLE이 설치가 안되어 있다면 없을 것이므로 "SOFTWARE"에 "키" 값을 추가 하여 ORACLE을 직접 생성한다. (대소문자 구분)

 

 

언어설정을 위하여 다음과 같은 값을 추가한다.

 - 새로 만들기 -> "문자열 값"
 NLS_LANG : KOREAN_KOREA.KO16MSWIN949

 

ORA-12170: TNS: 접속 시간 초과가 발생함

원격 클라이언트에서 Oracle Server 접속 시에

 

"ORA-12170: TNS: 접속 시간 초과가 발생함"

 

이란 오류가 발생 시, 서버측의 방화벽 설정을 살펴 볼 필요가 있다.

 

대부분의 경우, 방화벽을 해제한뒤 접근을 시도하면 접근이 가능하다.

 

접근 가능 함을 확인 했다면, 적절한 포트를 방화벽에서 오픈한 뒤 사용하도록 한다.

 

공유기를 사용한다면 공유기 방화벽 PORT와 윈도우의 방화벽 PORT 모두를 오픈해야 한다.