객체 타입 - 5

    슈퍼타입과 서브타입 간의 변환

    객체 지향 프로그래밍 언어에서 슈퍼타입의 변수는 서브타입의 인스턴스를 수용할 수 있다.

    그리고 슈퍼타입에 할당된 서브타입 인스턴스를 다시 서브타입 변수로 변환하여 서브타입 변수에 할당하는 것도 가능하다. 오라클에서도 동일하게 슈퍼타입 변수 또는 칼럼이 서브타입 인스턴스를 가질 수 있고, 인스턴스의 서브타입과 슈퍼타입 간의 변환이 가능하다. 타입 변환은 다음 두 가지로 분류할 수 있다.

    • 1. 서브타입에서 슈퍼타입으로의 변환: 슈퍼타입은 기본적으로 서브타입 인스턴스를 수용할 수 있다. 변환은 묵시적으로 수행될 수 있으며, 오류가 발생하지 않는다.
    • 2. 슈퍼타입에서 서브타입으로의 변환: 슈퍼타입에 저장된 서브타입 인스턴스를 서브타입으로 변환할 수 있다. 변환에는 함수 TREAT를 사용한다. TREAT 함수는 슈퍼타입에 저장된 인스턴스가 변환하려는 객체 타입에 맞지 않으면 오류를 발생시킨다.
    -- 변수의 타입 변환
    DECLARE
    	-- PL/SQL에서 슈퍼타입과 서브타입 간의 변환
        v1 person_type	:= person_type	('홍','길동','한성 종로','32번지');
        v2 employee_type:= employee_type('손','오공','화과산 수렴동','동굴', 1001, 9900, 10, NULL);
        v3 person_type;
        v4 employee_type;
    BEGIN
    	v3 := v1;	-- 정상, 동일 타입이므로 가능
        v3 := v2;	-- 정상, 슈퍼타입 변수는 서브타입 인스턴스를 수용할 수 있음
        v4 := TREAT(v3 as employee_type); -- 정상, v3의 employee_type을 employee_type 변수에 할당
        v3 := v1;
        v4 := TREAT(v3 as employee_type); -- 오류. person_type을 employee_type에 할당할 수 없음
    END;
    -- 테이블 데이터의 타입 변환
    SCOTT> DELETE FROM tb_person;
    SCOTT> REM SQL에서 슈퍼타입과 서브타입 간의 변환
    SCOTT> INSERT INTO tb_person VALUES(person_type('홍','길동','청학동 일번지'. ''));
    
    1 개의 로우가 만들어졌습니다.
    
    SCOTT> INSERT INTO tb_person VALUES(employee_type('손','오공','화과산 수렴동','동굴', 1001, 9900, 10, NULL));
    
    1 개의 로우가 만들어졌습니다.
    
    SCOTT> COL FULL_NAME FORMAT A10
    SCOTT> COL DISPLAY   FORMAT A68
    SCOTT> SELECT a.full_name() full_name, a.display() display
    		 FROM tb_person a;
             
    FULL_NAME	DISPLAY
    ----------  --------------------------------------------------------------------------
    홍 길동	  성:홍, 이름:길동, 기본주소:청학동 일번지, 상세주소:
    손 오공	  성:손, 이름:오공, 기본주소:화과산 수렴동, 상세주소:동굴, 사번:1001, 급여:9900, 부서번호:10
    
    

     슈퍼타입 person_type의 객체 테이블 tb_person에 person_type의 인스턴스 한 건과 서브 타입인 employee_type의 인스턴스 한 건을 INSERT했고 두 건 모두 정상적으로 INSERT된다. 두 건을 조회할 때 display메소드를 사용하여 데이터를 출력해보면 테이블에 삽입된 인스턴스가 원래의 타입을 보존하고 있음을 알 수 있다. 홍길동은 person_type의 display 메소드의 출력을 보이고 손오공은 employee_type의 display 메소드의 출력을 보이고 있다.

     

    --VALUE 함수를 이용한 타입 확인
    SCOTT> COL VALUE FORMAT A79
    SCOTT> SELECT VALUE(a) "VALUE"
    	     FROM tb_person a;
             
    VALUE(FAMILY_NAME, GIVEN_NAME, ADDRESS_1, ADDRESS_2)
    -------------------------------------------------------------------------------
    PERSON_TYPE('홍','길동','청학동 일번지', NULL);
    EMPLOYEE_TYPE('손','오공','화과산 수렴동','동굴',1001,9900,10,NULL);
    

    결과에서 확인할 수 있는 것처럼 홍길동은 person_type의 인스턴스고 손오공은 employee_type의 인스턴스다. 슈퍼타입 객체 테이블인 tb_person은 person_type 타입의 인스턴스와 employee_type 타입의 인스턴스 모두를 저장할 수 있다는 것을 보여주고 있다. 

    객체 타입의 진화 

    객체 타입은 사용하기가 간단하지는 않다. 또한 서브프로그램이나 패키지에 비해 정교한 만큼 제약도 많다. PL/SQL을 사용하여 서브프로그램이나 패키지 또는 트리거를 작성할 때 무언가 변경이 필요하면 소스코드를 수정한 후 CREATE OR REPLACE문을 사용하여 재컴파일했다. 그리고 앞에서 객체 타입 예제 또한 CREATE OR REPLACE TYPE문을 사용하여 객체 타입 명세와 본체를 재생성했다. 하지만 CREATE OR REPLACE TYPE문을 사용하여 객체 타입 person_type과 employee_type의 명세를 변경하는 것은 이제부터는 불가능하다, 이는 객체 타입이 가지는 제약인 '의존하는 오브젝트를 가진 객체 타입에 대해서는 CREATE OR REPLACE TYPE문을 사용할 수 없다.'라는 항목 때문이다. 이 제약에 관련된 사항을 설명하면

     

    1. 앞의 예제에서 person_type을 상속하여 employee_type을 생성했다. 이제 person_type에 의존하는 오브젝트 employee_type이 존재하므로 person_type에는 더 이상 CREATE OR REPLACE TYPE문을 사용할 수 없다.
    2. 앞의 예제에서 person_type에 기반하여 테이블 tb_person을 생성했다. 이제 person_type에 의존하는 또 다른 오브제트 tb_person이 존재한다. employee_type을 생성하지 않았다고 하더라도 person_type에는 더 이상 CREATE OR REPLACE TYPE문을 사용할 수 없다.
    3. 특이한 것 한 가지는 상속 관계에서 슈퍼타입에 기반한 테이블을 생성하면 이를 상속한 서브타입까지도 CREATE OR REPLACE TYPE문을 사용할 수 없다는 것이다. 앞의 예제에서는 person_type에 기반한 테이블 tb_person을 생성했다. 이때 tb_person은 person_type뿐만 아니라 employee_type에도 의존하게 된다. 테이블 tb_person이 person_type과 employee_type 둘 다를 수용할 수 있도록 하기 위해 person_type에서 상속한 서브타입까지 참조하는 것이다. 이제 person_type뿐만 아니라 person_type을 상속한 employee_type에도 더 이상 CREATE OR REPLACE TYPE문을 사용할 수 없다.
    4. 추가로 이와 같이 의존성을 가지는 다른 객체가 있는 경우가 아니더라도, 객체 타입에 한 번이라도 ALTER TYPE문을 사용하여 변경을 수행하면 이후로는 더 이상 CREATE OR REPLACE TYPE문을 사용하는 것이 불가능하다.

    의존되는 객체 타입에 대해서는 ALTER TYPE문만을 사용할 수 있다. 단 이는 객체 타입의 명세에 대한 제약이며, 객체 타입의 본체는 여전히 CREATE OR REPLACE TYPE BODY문을 사용할 수 있다. ALTER TYPE문을 사용하여 객체 타입에 변경을 가하는 것을 진화(Evolution)라고 한다. 진화는 객체 타입 명세에 대한 변경만을 말하며 객체타입 본체의 변경은 진화가 아니다. 객체 타입 진화의 유형은 다음과 같다.

    • 메소드의 추가 또는 삭제
    • 속성의 추가, 변경(길이, 정밀도, 스케일의 변경) 또는 삭제
    • 타입의 FINAL과 NOT FINAL의 변경

    주의할 점은 객체 타입에 변경을 가하는 것은 단순히 객체 타입 하나의 변경만으로 끝나지 않는다는 점이다.

    한 객체 타입의 변경은 이에 의존하는 모든 오브젝트에 영향을 준다. 예를 들어 객체 타입의 속성을 변경하면 이 객체 타입을 상속하는 모든 서브타입에도 동일한 속성 변경이 일어난다.(데이터베이스가 관리하는 내부적인 메타데이터에서 의존성을 가지는 모든 DB 오브젝트에 대한 변경이 수행된다.) 만약 이 객체 타입이나 이의 서브타입 중 하나에 기반한 테이블이 생성되어 있다면 해당 테이블에도 변경이 발생하게 된다. 이는 실질적으로 테이블에 DDL을 수행하는 것과 동일하다. 진화에 소요되는 시간은 테이블의 크기와 변경의 종류에 따라 달라질 것이다.

     

    메소드의 추가 또는 삭제

    진화를 통해 객체 타입 메소드를 추가하거나 삭제할 수 있다. 메소드의 변경은 지원하지 않는데, 변경을 위해서는 기존 메소드를 삭제하고 새로운 스펙으로 생성하면 된다. 메소드를 추가하거나 삭제할 때 다음 형식을 사용한다.

    ALTER TYPE 객체타입명 ADD 메소드스펙 { CASCADE | INVALIDATE };
    ALTER TYPE 객체타입명 DROP 메소드스펙 { CASCADE | INVALIDATE };
    -- 객체 타입의 진화: 메소드 추가
    ALTER TYPE employee_type
    	ADD MEMBER FUNCTION mail_label RETURN VARCHAR2 CASCADE;

    객체타입에 메소드 명세를 추가하면 객체 타입 본체에도 이 메소드 정의를 추가해야 된다. 이를 위해서는 전에 작성한 객체 타입 본체에 해당 메소드의 정의를 추가한 후 재컴파일하면 된다. 타입 명세에는 ALTER문을 사용해야 하지만, 본체에는 이러한 제약이 없으므로 CREATE OR REPLACE TYPE BODY문을 사용한다.

    -- 객체 타입의 진화: 메소드 삭제
    ALTER TYPE employee_type
      DROP MEMBER FUNCTION mail_label RETURN VARCHAR2 CASCADE;

    속성의 추가, 삭제, 변경

    속성의 추가와 삭제는 다음 형식을 사용한다.

    ALTER TYPE 객체타입명 ADD ATTRIBUTE (속성스펙 [, 속성스펙 ... ] )
    										{ CASCADE | INVALIDATE } ;
    ALTER TYPE 객체타입명 DROP ATTRIBUTE (속성명 [, 속성명 ... ] )
    										{ CASCADE | INVALIDATE } ) ;

    속성의 변경은 다음 형식을 사용한다.

    ALTER TYPE 객체타입명 MODIFY ATTRIBUTE (속성스펙 [, 속성스펙 ... ] )
    										( CASCADE | INVALIDATE } ;
    -- 객체 타입의 진화: 속성 추가
    ALTER TYPE employee_type
      ADD ATTRIBUTE (phone_number	VARCHAR2(11), gender VARCHAR2(1)) CASCADE;
    -- 객체 타입의 진화: 속성 변경
    ALTER TYPE employee_type
     MODIFY ATTRIBUTE (phone_number VARCHAR2(12)) CASCADE;
    -- 객체 타입의 진화: 속성 삭제
    ALTER TYPE employee_type
     DROP ATTRIBUTE (phone_number, gender) CASCADE;

    타입의 FINAL과 NOT FINAL의 변경

    FINAL과 NOT FINAL의 변경은 객체 타입이 상속될 수 있는 가능성을 변경한다. 단 이미 상속이 이루어져 서브타입이 존재하는 객체 타입에 대해서는 NOT FINAL로 변경할 수 없다. 사용하는 문장의 형식은 다음과 같다.

    ALTER TYPE 객체타입명 { FINAL | NOT FINAL } { CASCADE | INVALIDATE }
    -- 객체 타입의 진화: FINAL로 변경
    ALTER TYPE employee_type FINAL CASCADE;
    
    -- 객체 타입의 진화: NOT FINAL로 변경
    ALTER TYPE employee_type NOT FINAL CASCADE;

    'DATABASE > SQL, PL-SQL' 카테고리의 다른 글

    저장 서브프로그램 관리  (0) 2021.05.22
    객체 타입 - 4  (0) 2021.05.09
    객체 타입- 3  (0) 2021.05.06
    Object Type(객체 타입) - 2  (0) 2021.04.29
    Object Type(객체 타입) - 1  (0) 2021.04.17

    댓글