내용 목차
본 장에서는 Tibero의 객체 타입과 구성요소 동작방식에 대해서 설명한다.
Tibero 객체 타입은 사용자 정의 타입으로서 주문 또는 고객과 같은 실세계에 존재하는 개체를 표현하는 데 사용된다. NUMBER, VARCHAR 와 같은 기존 타입들을 사용하여 새로운 객체 타입을 정의할 수 있으며, 이전에 정의했던 객체 타입 혹은 컬렉션 타입도 타입을 정의하는데 이용할 수 있다.
또한 테이블을 생성할 때 컬럼의 타입으로 객체 타입을 명시하거나 해당 객체 타입 값만을 저장할 수 있도록 테이블을 생성할 수가 있다. 이러한 테이블을 객체 테이블이라고 한다.
Tibero는 객체를 관계형 모델의 확장으로써 구현한다. 이를 위해 SQL 문법이 확장되었으며, PSM 역시 확장되었다.
객체 타입은 데이터 타입의 한 종류이기 때문에 데이터 타입을 명시할 수 있는 대부분의 경우에 객체 타입 역시 사용이 가능하다. 테이블을 생성하는 경우 컬럼의 타입을 명시하는데 사용하거나 PSM을 정의하는 경우 변수의 타입을 명시하는 데에서도 사용할 수 있다. 타입을 정의하기 위해서 CREATE TYPE 구문 그리고 타입의 메소드가 존재할 경우 CREATE TYPE BODY 구문을 사용한다.
[예 6.1] 객체 타입
CREATE TYPE customer_type AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), MEMBER FUNCTION tostring RETURN VARCHAR); / CREATE TYPE BODY customer_type AS MEMBER FUNCTION tostring RETURN VARCHAR IS BEGIN RETURN custno || ':' || name || ':' || phone; END; END; /
객체 타입을 구성하는 요소는 다음의 2가지로 구성된다.
타입 | 설명 |
---|---|
속성 | 위의 예에서 custno, name, phone에 해당된다. 실제 데이터를 저장하기 위한 항목이다. |
메소드 | 위의 예에서 tostring에 해당된다. 해당 타입 값에 대해 정해진 연산을 수행하기 위해 설정한다. |
CREATE TYPE 문의 속성에 대해 제약 조건을 걸 수는 없지만, CREATE TABLE 문에서 타입을 사용할 경우에는 속성 값에 대한 제약 조건을 명시할 수 있다.
객체 타입을 통해 실제 데이터를 가지는 객체가 존재할 수 있는데, 이것을 객체 타입 값 또는 간단히 객체라고 한다. 하나의 객체 타입을 통해 만들어질 수 있는 객체는 실제 들어가는 데이터에 따라 여러 개가 존재할 수 있다.
다음은 테이블을 생성할 때 컬럼의 타입을 객체 타입으로 지정하고, 이러한 테이블에 실제 객체(객체 타입 값)를 저장하는 예제이다.
[예 6.2] 객체 타입 값
CREATE TABLE customer ( cust_obj customer_type, status VARCHAR(1)); INSERT INTO customer VALUES (customer_type(1, 'James', '111-222-3333'), 'V');
위 예에서 customer 테이블에 이름이 'James'인 customer_type 객체 타입의 객체가 하나 저장되었다. customer_type(...) 표현식은 디폴트 생성자라 부르는 것으로, 해당 객체 타입의 객체를 하나 만들 때 이용할 수 있는 문법 중 하나이다.
테이블에서 객체를 저장하는 형태는 테이블을 생성할 때 결정되며, 다음의 두 가지로 나눌 수 있다.
다음은 객체 테이블을 생성하는 CREATE TABLE 문의 예제이다.
객체 테이블을 생성하면 객체 타입의 속성에 해당하는 컬럼이 해당 테이블의 컬럼으로 생성된다. 그러므로 위의 예에서 customer_type_tab 테이블은 사용자 입장에서 3개의 컬럼을 가지는 테이블로 조회된다.
[예 6.4] 객체 테이블 조회 (1)
SQL> desc customer_type_tab; COLUMN_NAME TYPE CONSTRAINT ---------------------------------------- ------------------ -------------------- CUSTNO NUMBER NAME VARCHAR(40) PHONE VARCHAR(20)
객체 테이블은 객체를 저장하고 있으므로, 실제 객체를 테이블에서 꺼내올 수도 있게 되는데, 이 때 사용하는 문법이 VALUE(x) 표현식이다.
다음과 같이 객체 테이블 별칭(x)을 인자로 표현식에 주어서 객체 테이블에 저장되어 있는 객체에 접근할 수가 있다.
[예 6.5] 객체 테이블 조회 (2)
INSERT INTO customer_type_tab VALUES(customer_type(1, 'James', '111-222-3333')); INSERT INTO customer_type_tab VALUES(2, 'Bob', '444-555-6666'); DECLARE c1 customer_type; BEGIN SELECT VALUE(x) into c1 FROM customer_type_tab x where custno = 1; dbms_output.put_line(c1.tostring()); END; /
위의 예에서 보는 것처럼, 객체 테이블에 Insert를 수행할 때는 객체 표현식(위에서는 디폴트 생성자를 사용했다) 하나만을 명시해도 Insert가 가능하고, 각각의 속성 값을 일일이 지정하는 형태로도 Insert가 가능함을 알 수가 있다.
같은 타입의 데이터를 모아서 하나의 값으로 만들어 처리하고 싶을 때 사용하는 것이 컬렉션 타입이다. Tibero 에서 컬렉션 타입은 객체 타입과 마찬가지로 사용자가 직접 정의하는 타입이며, 가변 배열 혹은 중첩 테이블의 두 가지 형태로 제공된다. 컬렉션 타입 역시 사용자가 새로운 객체 타입을 생성할 때 속성의 타입으로서 명시될 수 있다. 자세한 내용은 “제7장 컬렉션 타입의 사용”을 참고한다.
다음의 예는 중첩 테이블 타입을 하나 정의하고 이러한 타입 속성을 가지는 객체 타입을 정의하는 CREATE TYPE 문법의 예를 보여준다.
CREATE TYPE customer_ntab_type AS TABLE OF customer_type; / CREATE TYPE int_group_type AS OBJECT ( group_no NUMBER, members customer_ntab_type); /
본 절에서는 Tibero 객체를 구성하는 여러 가지 요소에 해서 설명한다.
본 절에서는 SQL 내에서 사용되는 객체의 구성요소에 대해서 설명한다.
객체의 값 자체가 NULL일 경우 쪼갤 수 없는 객체 혹은 NULL 객체라고 한다. 쪼갤 수 없는 객체는 모든 속성값이 NULL인 객체와는 다른 객체이다(즉, 이 경우는 NULL이 아닌 객체이다). NULL이 아닌 객체의 경우, 특정 속성의 값은 NULL을 가질 수도 있으며 이 속성값은 프러시저 혹은 함수를 통해 NULL이 아닌 값으로 변경될 수 있다. 그러나 NULL 객체인 경우 객체의 속성값을 바꾸는 것은 불가능하며, 객체의 메소드를 호출하는 것도 불가능하다.
다음은 컬럼 객체를 가지는 테이블의 객체 컬럼에 NULL 객체와 NULL 속성값을 가지는 NULL이 아닌 객체를 Insert하는 예제이다.
[예 6.6] NULL 객체와 객체의 NULL 속성
CREATE TYPE customer_type2 AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), MEMBER FUNCTION tostring RETURN VARCHAR DETERMINISTIC); / CREATE TYPE BODY customer_type2 AS MEMBER FUNCTION tostring RETURN VARCHAR DETERMINISTIC IS BEGIN RETURN custno || ':' || name || ':' || phone; END; END; / CREATE TABLE customer2 ( cust_obj customer_type2, status VARCHAR(1)); INSERT INTO customer2 VALUES (Null, 'I'); INSERT INTO customer2 VALUES (customer_type2 (NULL, NULL, NULL), 'V');
객체 테이블의 행 객체는 NULL 객체일 수가 없다. 또한 컬렉션의 경우 NULL 컬렉션과 구성 요소가 하나도 들어있지 않은 빈 컬렉션은 NULL 컬렉션이 아니며 서로 다른 컬렉션이다.
일반 테이블에 제약 조건을 정의할 수 있는 것처럼 객체 타입을 사용한 테이블에도 제약 조건을 정의할 수 있다. 다만 제약 조건은 객체 타입의 포함 관계 트리에서 맨 아래에 존재하는 속성에 대해서만 정의할 수 있다. 맨 아래의 속성은 객체 타입 속성일 수 없으므로, 이러한 속성은 내장 타입을 가지게 된다.
다음은 객체 테이블을 생성할 때 객체 타입의 속성 하나를 객체 테이블의 기본 키로 지정하는 예이다.
[예 6.7] 객체 테이블 생성에 객체 테이블을 기본 키로 지정
CREATE TABLE customer_type_tab2 of customer_type2 ( custno PRIMARY KEY);
테이블이 객체 컬럼을 가질 때에도 해당 객체의 속성에 제약 조건을 정의할 수 있는데, 이 때는 점(.) 표기법으로 정의할 수 있다.
[예 6.8] 객체 컬럼의 제약 조건 설정
CREATE TABLE customer3 ( cust_obj customer_type2, status VARCHAR(1), CONSTRAINT cust_check_cons CHECK (cust_obj.custno IS NOT NULL));
인덱스 컬럼이 될 수 있는 조건은 제약 조건을 정의할 수 있는 컬럼의 조건과 동일하다: 객체 타입의 포함 관계 트리에서 맨 아래에 존재하는 속성만을 인덱스 컬럼으로 지정할 수 있다. 객체 컬럼의 경우 점(.) 표기법으로 정의할 수 있다.
함수 기반 인덱스를 생성하는 경우 함수의 반환 타입이 객체 타입일 경우는 생성이 허용되지 않는다. 만일 객체 테이블에 대해 함수 기반 인덱스를 정의하면서 기반 객체 타입의 함수 멤버 메소드를 호출하는 경우 다음과 같이 테이블 별칭 다음 점(.) 표기법으로 정의할 수 있다.
테이블의 컬럼이 객체 타입인 경우 이 객체의 속성 값을 Select하는 경우 점(.) 표기법을 사용한다. SELECT 문에서 점(.) 표기법을 사용할 때 한 가지 주의할 점은 객체 컬럼에 대해 점(.) 표기법을 사용할 때 항상 테이블 별칭을 점(.) 표기법과 앞에 표기해 주어야 한다.
[예 6.11] 테이블의 컬럼이 객체 타입인 경우 Select
SELECT cust_obj.phone FROM customer3; -- 구문 에러 SELECT x.cust_obj.phone FROM customer3 x; -- 올바른 문장
VALUE(x) 표현식은 SQL에서 객체 테이블의 테이블 별칭을 인자로 받아 현재 행에 해당하는 행 객체를 반환하는 표현식이다.
[예 6.12] VALUE(x) 표현식
INSERT INTO customer_type_tab2 values (1, 'David', '555-666-7777'); DECLARE c1 customer_type2; BEGIN SELECT VALUE(x) into c1 FROM customer_type_tab2 x where custno = 1; dbms_output.put_line(c1.tostring()); END; /
위의 예처럼 객체 테이블의 속성값을 조회하는 것이 아니고 객체의 멤버 메소드를 호출하는 경우 경우에는 VALUE(x) 표현식이 필요하다. VALUE(x) 표현식은 다음과 같이 UPDATE 문을 수행하는 경우 사용자 정의 생성자(아래에 설명)가 생성한 객체로 객체 테이블의 현재 객체를 덮어쓰는 경우에도 사용할 수 있다.
[예 6.13] VALUE(x) 표현식을 사용한 update
CREATE OR REPLACE TYPE customer_type3 AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), CONSTRUCTOR FUNCTION customer_type3 RETURN SELF AS RESULT); / CREATE OR REPLACE TYPE BODY customer_type3 AS CONSTRUCTOR FUNCTION customer_type3 RETURN SELF AS RESULT IS BEGIN custno := -1; name := 'Untitled'; phone := 'N/A'; RETURN; END; END; / CREATE TABLE customer_type_tab3 OF customer_type3; INSERT INTO customer_type_tab3 values (1, 'David', '555-666-7777'); UPDATE customer_type_tab3 x SET VALUE(x) = customer_type3() WHERE custno = 1;
객체 타입의 메소드는 PSM 함수 혹은 프러시저일 수 있으며 해당 객체에 대해 수행할 연산을 명시한다.
해당 객체에 대한 연산을 정의할 때 일반적으로 사용하는 메소드 형태이다. 연산을 적용할 객체를 명시할 때 점(.)을 사용한 특별한 문법을 이용해서 멤버 메소드를 호출할 수 있다.
PSM 패키지 내의 함수 혹은 프러시저를 정의하는 것과 유사하게 객체 타입을 정의할 때 타입 내부에 정의하는 함수 혹은 프러시저이다. 정적 메소드는 객체 타입 내부에 존재한다는 것 빼고는 일반 패키지 함수 혹은 프러시저와 다른 점은 없다.
특정 연산을 수행한 결과를 통해서 해당 타입의 객체를 생성하고 싶을 때 이용할 수 있다. 사용자는 이러한 생성자 메소드를 이용해서 새로운 객체를 생성할 수도 있고, 따로 생성자를 정의하지 않았을 경우에도 디폴트 생성자 메소드 문법을 통해 객체를 생성할 수가 있다.
다음은 객체의 멤버 메소드를 호출하는 예이다.
SELECT x.cust_obj.tostring() FROM customer x;
해당 함수 혹은 프러시저가 현재 주어진 객체의 값에 따른 연산을 수행할 때 멤버 메소드를 통해 이러한 연산을 정의한다. CREATE TYPE 문 내에서 멤버 메소드를 정의할 때는 MEMBER FUNCTION 또는 MEMBER PROCEDURE와 같이 앞에 MEMBER를 명시한다. 이렇게 정의된 멤버 메소드는 다음과 같이 객체 표현식 다음에 점(.) 표기법을 사용하여 호출할 수 있다.
점 앞에 오는 것은 해당 객체의 값을 가질 수 있는 객체 표현식이고, 점 다음에는 그 객체의 객체 타입에서 정의하고 있는 멤버 메소드의 이름을 명시한다 SQL에서 멤버 메소드를 호출할 때는 메소드에 건네줄 매개변수가 없는 경우에도 다음과 같이 항상 괄호를 붙여 주어야 한다.
멤버 메소드에는 첫 번째 매개변수로서 정해진 하나의 매개변수가 항상 전달되는 것으로 간주되는데, 이 매개변수를 SELF고 한다. 이 SELF 매개변수에는 멤버 메소드를 호출할 때 명시한 대상 객체의 값이 매개변수의 값으로 전달이 된다.
멤버 메소드를 정의할 때 첫 번째 매개변수로 이 SELF 매개변수를 직접 명시할 수 있으나, 명시하지 않아도 명시한 것으로 간주하며 문법 에러는 발생하지 않는다. 타입의 BODY에서 대상 객체의 속성 값을 명시할 때 SELF 및 점(.) 표기법을 이용해 속성 값을 명시할 수도 있고, SELF와 점을 생략해도 명시가 가능하다. (매개 변수와 이름이 겹치지 않을 경우)
[예 6.16] SELF 매개변수 생성
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, MEMBER FUNCTION around RETURN NUMBER, MEMBER FUNCTION area(SELF IN OUT NOCOPY rectangle_type) RETURN NUMBER); / CREATE OR REPLACE TYPE BODY rectangle_type AS MEMBER FUNCTION around RETURN NUMBER IS BEGIN RETURN 2 * (x + y); END; MEMBER FUNCTION area RETURN NUMBER IS BEGIN RETURN SELF.x * SELF.y; END; END; /
객체 테이블에 저장되어 있는 객체에 대한 멤버 메소드를 호출하는 경우 테이블 별칭과 점(.) 표기법을 이용하여 다음과 같이 호출할 수가 있다. 또한 행 객체를 나타내는 VALUE(x) 표현식으로도 가능하다.
[예 6.17] 멤버 메소드 호출
CREATE TABLE rect_tab of rectangle_type; INSERT INTO rect_tab VALUES(2, 4); INSERT INTO rect_tab VALUES(rectangle_type(8, 3)); SELECT x.around(), x.area() FROM rect_tab x; SELECT VALUE(x).around(), VALUE(x).area() FROM rect_tab x;
객체를 비교하거나 또는 정렬하려면 일단 두 객체의 기반이 되는 객체 타입이 같아야 하며, 정해진 형태의 멤버 메소드를 통해서 비교 연산이 수행된다. 만일 이러한 멤버 메소드가 존재하지 않을 경우 에러가 발생한다(단, 동등 비교(equal) 및 비동등 비교(inequal)에 대해서는 특수한 규칙을 통해 허용된다).
비교를 수행하는 멤버 메소드는 두 가지(map 메소드/order 메소드) 형태로 존재하는데, 하나의 객체 타입에 대해서 이 둘 중 하나만을 정의할 수 있다.
하나의 내장 타입 값을 반환하는 메소드이다. 이 값을 기준으로 객체를 비교하거나, 정렬하는 데 이용할 수 있다. 객체 표현식에 대해 SQL에서 ORDER BY를 구사하면, 자동적으로 이 map 메소드가 각 객체에 대해 호출된다. map 메소드가 정의되어 있을 때 다음의 SQL에서 컬럼 c1과 컬럼 c2가 해당 객체 타입일 경우 위 SQL 은 실제로 다음과 같이 수행된다.
SELECT 1 FROM t1 x WHERE x.c1 > x.c2;
SELECT 1 FROM t1 x WHERE x.c1.map() > x.c2.map();
다음은 비교 연산을 위해 해당 객체 타입에 map 메소드를 정의하는 예이다.
[예 6.18] 객체 타입에 map 메소드 정의
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, MAP MEMBER FUNCTION area RETURN NUMBER); / CREATE OR REPLACE TYPE BODY rectangle_type AS MAP MEMBER FUNCTION area RETURN NUMBER IS BEGIN RETURN SELF.x * SELF.y; END; END; /
비교할 두 개의 객체를 매개변수로 받아서 비교 결과를 반환하는 메소드이다. 이 중 첫 번째 객체는 SELF를 통해 전달되므로, SELF와 비교할 나머지 객체만을 추가 매개변수로 전달하면 된다. order 메소드는 비교 연산자를 통한 객체의 비교에서는 자동적으로 호출되나, ORDER BY에서는 호출되지 않는다.
order 메소드의 반환값은 음수, 0, 양수의 숫자형 값을 반환하여야 하며 이 값들은 각각 SELF 객체가 비교하는 객체보다 작거나 또는 같거나 또는 더 큼을 의미한다.
[예 6.19] order 메소드
CREATE OR REPLACE TYPE address_type AS OBJECT ( name VARCHAR(20), addr VARCHAR(50), city VARCHAR(20), state VARCHAR(2), zip VARCHAR(5), ORDER MEMBER FUNCTION cmp(v address_type) RETURN NUMBER); / CREATE OR REPLACE TYPE BODY address_type AS ORDER MEMBER FUNCTION cmp(v address_type) RETURN NUMBER IS BEGIN IF SELF.zip < v.zip THEN RETURN -1; ELSIF SELF.zip > v.zip THEN RETURN 1; ELSIF state < v.state THEN RETURN -1; ELSIF state > v.state THEN RETURN 1; ELSIF city < v.city THEN RETURN -1; ELSIF city > v.city THEN RETURN 1; ELSIF addr < v.addr THEN RETURN -1; ELSIF addr > v.addr THEN RETURN 1; ELSE RETURN 0; END IF; END; END; /
만일 map 메소드도 order 메소드도 존재하지 않는데 동등 비교 (equal) 또는 비동등 비교 (inequal) 연산을 수행할 경우 이 비교는 객체 타입의 포함 관계 트리에서 맨 아래에 존재하는 속성(즉, 내장 타입 속성) 각각에 대해 비교를 수행하고, 그 결과들을 AND 연산(비동등 비교일 때 OR 연산)으로 묶은 것과 같은 것으로 간주되어 정상 수행된다. 즉, 만일 위의 address_type에서 order 메소드가 정의되지 않았다고 했을 때 다음의 SQL이 수행되면 이 SQL은 실제로 다음과 같이 수행된다.
[예 6.20] 메소드 비교
SELECT 1 FROM t1 x WHERE x.c1 = x.c2;
SELECT 1 FROM t1 x WHERE x.c1.name = x.c2.name AND x.c1.addr = x.c2.addr AND x.c1.city = x.c2.city AND x.c1.state = x.c2.state AND x.c1.zip = x.c2.zip;
정적 메소드는 특정 객체에 대해 수행할 동작을 정의하는 것이 아닌 단순히 객체 타입 내에 정의되는 함수 또는 프러시저이다. 그러므로 정적 메소드에서는 미리 정의된 SELF 매개변수가 존재하지 않는다. 정적 메소드를 호출하기 위해서는 메소드 이름 앞에 점(.)을 사용하여 객체 타입 이름을 선행한다.
생성자 메소드는 수행의 결과로 해당 타입의 객체를 반환하는 함수이다. 이것은 미리 정의되어 있는 디폴트 생성자와 사용자가 정의하는 사용자 정의 생성자로 나눌 수 있다.
디폴트 생성자는 생성자의 매개변수로 해당 객체 타입의 속성 값을 순서대로 명시하여 호출하는 생성자이다. 예를 들어 위의 address_type에 대한 디폴트 생성자를 호출하는 예는 다음과 같다.
사용자 정의 생성자 메소드는 사용자가 해당 타입의 객체 생성을 위해 객체 타입 내에 직접 정의하는 메소드 함수이다. 사용자 정의 생성자를 정의할 때 어떤 매개변수를 전달할 지는 사용자가 자유롭게 정할 수 있다. 만일 생성자 내에서 특정 속성에 대해 아무런 값도 지정하지 않았다면, 해당 속성의 값은 NULL이 된다.
사용자 정의 생성자 메소드의 정의는 다음의 예와 같이 CONSTRUCTOR FUNCTION으로 시작하여 RETURN SELF AS RESULT로 끝난다. 생성자의 이름은 객체 타입의 이름과 일치해야 한다.
[예 6.23] 사용자 정의 생성자 메소드
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, CONSTRUCTOR FUNCTION rectangle_type ( SELF IN OUT NOCOPY rectangle_type, n NUMBER) RETURN SELF AS RESULT); / CREATE OR REPLACE TYPE BODY rectangle_type AS CONSTRUCTOR FUNCTION rectangle_type( SELF IN OUT NOCOPY rectangle_type, n NUMBER) RETURN SELF AS RESULT IS BEGIN SELF.x := n; y := n; RETURN; END; END; /
사용자 정의 생성자 메소드의 첫 번째 매개변수는 멤버 메소드와 마찬가지로 SELF 를 명시할 수 있으며 명시하지 않아도 명시한 것으로 간주된다. 메소드의 BODY 부분에서는 이 SELF 객체 변수의 값을 결정하고, 함수가 종료될 경우에는 단일 RETURN 문(RETURN 문 뒤에 함수가 반환할 값이 오지 않는)으로 메소드를 종료하여야만 한다. 사용자 정의 생성자가 생성하는 객체의 값은 이 SELF 객체 변수의 값이 된다.
본 절에서는 Tibero 객체의 실제 동작과 관련한 몇 가지 내용을 설명한다.
객체는 속성들의 집합으로 구성되며, 각각의 속성 역시 객체가 될 수 있기 때문에(단, 순환 참조는 허용하지 않는다) 객체 타입을 정의하고 나면 이것은 객체 간의 포함 관계를 나타내는 하나의 Tree로 표현이 가능해진다. Tree에서 단말에 위치하는 속성은 객체 타입 속성일 수 없으며 내장 타입을 가지는 속성이 된다.
객체가 테이블에 저장될 때는 한 객체가 하나의 값으로 합쳐져서 저장되지 않고 Tree에서 단말에 위치하는 내장 타입 속성들의 각 값으로 찢어져서 저장된다. 다시 말해, 객체가 저장되어 있는 테이블의 하나의 컬럼이 객체 자체에 대한 컬럼이 될 수는 없으며 NUMBER, VARCHAR2와 같은 내장 타입 컬럼과 가변 배열 컬럼들로 구성된 여러 개의 컬럼들을 사용해 해당 객체를 저장하게 된다.
테이블을 생성하는 경우 사용자가 명시한 컬럼의 타입이 객체 타입일 경우 Tibero는 내부적으로 이런 내장 타입 컬럼들을 숨겨진 컬럼의 형태로 만들고 추가로 컬럼을 하나 더 추가하게 되는데, 이 컬럼(NULL 지시자 컬럼)에는 해당 객체를 구성하는 객체들 중(객체의 속성 값 또한 임의의 객체 타입의 객체가 될 수 있으므로) 누가 NULL이고 누가 NULL이 아닌지에 대한 정보를 담게 된다. 그러나 단말 속성(내장 타입 속성)이 NULL 여부에 대한 정보는 NULL 지시자 컬럼에 들어가지 않고, 나머지 (내장 타입에 대한) 숨겨진 컬럼을 사용해 이 정보를 저장한다.
객체 테이블의 경우 객체 테이블이 기반하는 객체 타입을 구성하는 각각의 속성에 대해서 객체 테이블의 컬럼을 생성하며 컬럼의 이름은 속성의 이름을 따라간다. 기반 객체 타입의 특정 속성이 객체 타입 속성일 경우 위에서 기술한 대로(즉, 일반 테이블에 사용자가 객체 타입의 컬럼을 명시했을 때와 같이) 숨겨진 컬럼들이 내부적으로 추가된다.
객체 테이블에서 VALUE(x) 표현식을 사용하여 객체 테이블의 객체에 접근할 경우 이 객체는 객체의 포함관계 Tree 맨 아래에 있는 객체부터 디폴트 생성자를 사용하여 객체들을 생성하고, 마지막으로 가장 상위 단계의 객체들 그리고 내장 타입 속성 값들을 모아 최종 객체 타입의 디폴트 생성자를 호출해서 객체 테이블의 객체를 생성한다.
이때 디폴트 생성자가 사용자에 의해 가려졌을 경우(매개변수의 타입과 갯수, 순서가 디폴트 생성자와 동일한 생성자)라 하더라도 여전히 시스템에서 정의한 디폴트 생성자로 객체를 생성한다.
객체 식별자를 이용해 객체 테이블에 저장되는 객체를 유일하게 식별할 수 있다. 객체 식별자는 객체 테이블을 생성하는 경우 자동생성형과 기본키 기반형 중 하나를 선택할 수가 있다.
따로 지정하지 않으면 자동생성형 객체 식별자가 객체 테이블의 숨겨진 컬럼(OID 컬럼)으로서 할당이 된다. 객체 테이블에 객체를 하나 Insert할 때마다, 분산 환경까지 고려해서 전역적으로 유일한 16Bytes 값이 생성되며 이것이 OID 컬럼의 값으로서 저장이 된다. 이것은 CREATE TABLE을 수행할 때 OID 컬럼의 DEFAULT 값이 SYS_GUID() 내장 함수로 선언된 것과 동일한 동작을 한다.
객체 테이블을 만들 때 기본키를 지정한다면 해당 객체 테이블의 객체 식별자로서 사용할 수가 있다. CREATE TABLE 문에 OBJECT IDENTIFIER IS PRIMARY KEY 절을 추가하면서 생성하는 객체 테이블은 자동생성형 OID 컬럼을 만들지 않고 기본키의 값을 객체 식별자의 값으로 사용한다. 기본키 기반형 객체 식별자는 해당 테이블의 기본키 값을 기반으로 하고 있으므로, 유일성은 해당 객체 테이블 내에서만 보장된다. 만일 기본키의 길이가 16Bytes보다 작은 경우 이것은 공간의 절약을 의미한다.
VARRAY가 테이블의 컬럼으로 저장될 때는 실제로도 하나의 컬럼으로 저장된다. VARRAY 타입 값의 최대 길이는 요소 타입의 최대 길이를 VARRAY 타입의 최대 요소 갯수로 곱한 값에 약간의 오버헤드를 추가한 값이다.
해당 VARRAY 타입 값의 가능한 최대 길이가 VARCHAR2의 최대 길이를 넘을 경우 이 VARRAY 컬럼을 가지는 테이블을 생성할 때 긴 길이의 VARRAY 값을 저장할 수 있도록 하는 LOB 세그먼트도 같이 생성이 된다. 하지만 실제 값을 저장할 때는 LOB 세그먼트의 존재 유무와는 관계 없이 각각의 값 별로 VARCHAR2의 최대 길이보다 작을 경우는 그대로 테이블에 저장되고, 그렇지 않을 경우는 LOB 세그먼트에 저장된다.
다음은 객체 생성자의 주요 동작방식에 대한 설명이다.
생성자 가리기
만일 사용자가 디폴트 생성자와 똑같이 생긴(매개변수의 타입과 갯수, 순서가 디폴트 생성자와 똑같은) 생성자를 정의했을 경우 디폴트 생성자는 사용자에 의해 호출될 수 없으며 사용자가 정의한 생성자에 의해 가려진다. 사용자 정의 생성자는 서브타입으로 상속되지 않기 때문에 서브타입에서 정의하는 생성자로 가려지지 않는다.
생성자 오버로딩
생성자도 일반 타입 메소드와 마찬가지로 오버로딩(메소드 이름이 같지만 매개변수의 타입과 갯수, 순서가 다른 메소드)할 수 있다. 이것은 특정 객체 타입의 객체를 생성하기 위한 생성자가 동시에 여러 개 존재할 수 있다는 의미이다.
생성자의 사용
생성자는 표현식의 일종으로 일반 컬럼 및 함수가 사용될 수 있는 곳이라면 생성자도 사용이 가능하다. SQL에서 생성자를 호출하기 위해서는 생성자의 인자가 없더라도 항상 괄호를 붙여 주어야 한다. 생성자를 정의할 때는 SELF를 명시할 수 있으나, 호출할 때는 SELF에 해당하는 매개변수를 명시할 수 없다. CREATE TABLE 또는 ALTER TABLE의 DEFAULT 절 그리고 CHECK 제약 조건에는 사용자 정의 생성자가 올 수 없으며 디폴트 생성자만 올 수 있다.