> For the complete documentation index, see [llms.txt](https://docs.tibero.com/tibero-manuals/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tibero.com/tibero-manuals/7.2.6.manuals/development-guide/object-type.md).

# 오브젝트 타입의 사용

Tibero의 오브젝트 타입과 구성요소 동작 방식에 대해서 설명합니다.

## 개요

Tibero 오브젝트 타입은 사용자 정의 타입으로서 주문 또는 고객과 같은 실세계에 존재하는 개체를 표현하는 데 사용됩니다. NUMBER, VARCHAR와 같은 기존 타입들을 사용하여 새로운 오브젝트 타입을 정의할 수 있으며, 이전에 정의했던 오브젝트 타입 혹은 컬렉션 타입도 타입을 정의하는 데 이용할 수 있습니다.

또한 테이블을 생성할 때 컬럼의 타입으로 오브젝트 타입을 명시하거나 해당 오브젝트 타입 값만을 저장할 수 있도록 테이블을 생성할 수가 있습니다. 이러한 테이블을 오브젝트 테이블이라고 합니다.

오브젝트 타입의 기본 개념과 메소드를 정의하는 방법, 타입의 상속과 다형성 등 PSM 언어 관점의 내용은 "tbPSM 안내서"의 [오브젝트 타입](/tibero-manuals/7.2.6.manuals/tbpsm-guide/object-type.md)에서 설명합니다. 본 장에서는 테이블과 SQL 문장에서 오브젝트 타입을 사용하는 방법을 중심으로 설명합니다.

## 주요 개념

Tibero는 오브젝트를 관계형 모델의 확장으로써 구현합니다. 이를 위해 SQL 문법이 확장되었으며, PSM 역시 확장되었습니다.

### 오브젝트 타입

오브젝트 타입은 데이터 타입의 한 종류이기 때문에 데이터 타입을 명시할 수 있는 대부분의 경우에 오브젝트 타입 역시 사용이 가능합니다. 테이블을 생성하는 경우 컬럼의 타입을 명시하는데 사용하거나 PSM을 정의하는 경우 변수의 타입을 명시하는 데에서도 사용할 수 있습니다. 타입을 정의하기 위해서 CREATE TYPE 구문 그리고 타입의 메소드가 존재할 경우 CREATE TYPE BODY 구문을 사용합니다. 두 구문의 상세 문법은 "Tibero SQL 참조 안내서"의 [CREATE TYPE](/tibero-manuals/7.2.6.manuals/sql-reference-guide/data-definition-language/create-type.md)과 [CREATE TYPE BODY](/tibero-manuals/7.2.6.manuals/sql-reference-guide/data-definition-language/create-type-body.md)를 참고합니다.

다음은 고객 타입을 정의하는 예입니다.

**\[예 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가지 구성요소로 구성됩니다.

<table><thead><tr><th width="193">구성요소</th><th>설명</th></tr></thead><tbody><tr><td>Attribute</td><td><ul><li>위의 예에서 custno, name, phone에 해당됨</li><li>실제 데이터를 저장하기 위한 항목</li></ul></td></tr><tr><td>메소드</td><td><ul><li>위의 예에서 tostring에 해당됨</li><li>해당 타입 값에 대해 정해진 연산을 수행하기 위해 설정</li></ul></td></tr></tbody></table>

CREATE TYPE 문의 Attribute에 대해 제약 조건을 걸 수는 없지만, CREATE TABLE 문에서 타입을 사용할 경우에는 Attribute 값에 대한 제약 조건을 명시할 수 있습니다.

### 오브젝트 타입 값(**오브젝트**)

오브젝트 타입을 통해 실제 데이터를 가지는 오브젝트가 존재할 수 있는데, 이것을 오브젝트 타입 값 또는 간단히 오브젝트라고 합니다. 하나의 오브젝트 타입을 통해 만들어질 수 있는 오브젝트는 실제 들어가는 데이터에 따라 여러 개가 존재할 수 있습니다.

다음은 테이블을 생성할 때 컬럼의 타입을 오브젝트 타입으로 지정하고, 이러한 테이블에 실제 오브젝트(오브젝트 타입 값)를 저장하는 예제입니다.

**\[예 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 문법에서 컬럼의 타입을 지정하는 부분에 오브젝트 타입을 명시하면 테이블의 컬럼 형태로 오브젝트가 저장됩니다. 이러한 오브젝트를 컬럼 오브젝트라고 합니다.<br>
* **오브젝트 테이블 형태**\
  하나의 오브젝트 타입의 오브젝트들만을 저장할 수 있는 테이블을 만들 수도 있는데, 이러한 테이블을 오브젝트 테이블이라고 합니다. 이 때 생성되는 오브젝트를 행 오브젝트라고 합니다.<br>

다음은 오브젝트 테이블을 생성하는 CREATE TABLE 문의 예제입니다.

**\[예 3] 오브젝트 테이블 생성**

```
CREATE TABLE customer_type_tab of customer_type;
```

오브젝트 테이블을 생성하면 오브젝트 타입의 Attribute에 해당하는 컬럼이 해당 테이블의 컬럼으로 생성됩니다. 그러므로 위의 예에서 customer\_type\_tab 테이블은 사용자 입장에서 3개의 컬럼을 가지는 테이블로 조회됩니다.

**\[예 4] 오브젝트 테이블 조회 (1)**

```
SQL> desc customer_type_tab;

COLUMN_NAME                              TYPE               CONSTRAINT
---------------------------------------- ------------------ --------------------
CUSTNO                                   NUMBER
NAME                                     VARCHAR(40)
PHONE                                    VARCHAR(20)
```

오브젝트 테이블은 오브젝트를 저장하고 있으므로, 실제 오브젝트를 테이블에서 꺼내올 수도 있게 되는데, 이때 사용하는 문법이 VALUE(x) 표현식입니다.

다음과 같이 오브젝트 테이블 별칭(x)을 인자로 표현식에 주어서 오브젝트 테이블에 저장되어 있는 오브젝트에 접근할 수가 있습니다.

**\[예 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');

set serveroutput on
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가 가능하고, 각각의 Attribute 값을 일일이 지정하는 형태로도 Insert가 가능함을 알 수가 있습니다.

### 컬렉션 사용

같은 타입의 데이터를 모아서 하나의 값으로 만들어 처리하는 경우 사용하는 것이 컬렉션 타입입니다. Tibero에서 컬렉션 타입은 오브젝트 타입과 마찬가지로 사용자가 직접 정의하는 타입이며, CREATE TYPE 문으로 생성하는 컬렉션 타입은 배열 혹은 네스티드 테이블의 두 가지 형태로 제공됩니다. 컬렉션 타입 역시 사용자가 새로운 오브젝트 타입을 생성할 때 Attribute의 타입으로서 명시될 수 있습니다. 자세한 내용은 “[컬렉션 타입의 사용](/tibero-manuals/7.2.6.manuals/development-guide/collection-type.md)”을 참고합니다.

다음의 예는 네스티드 테이블 타입을 하나 정의하고 이러한 타입 Attribute를 가지는 오브젝트 타입을 정의하는 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** 내에서의 오브젝트 사용

본 절에서는 SQL 내에서 사용되는 오브젝트의 구성요소에 대해서 설명합니다.<br>

#### **NULL 오브젝트와 오브젝트의 NULL Attribute**

오브젝트의 값 자체가 NULL일 경우 쪼갤 수 없는 오브젝트 혹은 NULL 오브젝트라고 합니다. 쪼갤 수 없는 오브젝트는 모든 Attribute 값이 NULL인 오브젝트와는 다른 오브젝트입니다(즉, 이 경우는 NULL이 아닌 오브젝트입니다). NULL이 아닌 오브젝트의 경우 특정 Attribute의 값은 NULL을 가질 수도 있으며 이 Attribute 값은 프러시저 혹은 함수를 통해 NULL이 아닌 값으로 변경될 수 있습니다. 그러나 NULL 오브젝트인 경우 오브젝트의 Attribute 값을 바꾸는 것은 불가능하며, 오브젝트의 메소드를 호출하는 것도 불가능합니다.

다음은 컬럼 오브젝트를 가지는 테이블의 오브젝트 컬럼에 NULL 오브젝트와 NULL Attribute 값을 가지는 NULL이 아닌 오브젝트를 Insert하는 예제입니다.

**\[예 6] NULL 오브젝트와 오브젝트의 NULL Attribute**

```
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');
```

{% hint style="warning" %}
**주의**

오브젝트 테이블의 행 오브젝트는 NULL 오브젝트일 수가 없습니다. 또한 컬렉션의 경우 NULL 컬렉션과 구성요소가 하나도 들어있지 않은 빈 컬렉션은 NULL 컬렉션이 아니며 서로 다른 컬렉션입니다.
{% endhint %}

#### **테이블 제약 조건**

일반 테이블에 제약 조건을 정의할 수 있는 것처럼 오브젝트 타입을 사용한 테이블에도 제약 조건을 정의할 수 있습니다. 다만 제약 조건은 오브젝트 타입의 포함 관계 트리에서 맨 아래에 존재하는 Attribute에 대해서만 정의할 수 있습니다. 맨 아래의 Attribute는 오브젝트 타입 Attribute일 수 없으므로, 이러한 Attribute는 내장 타입을 가지게 됩니다.

다음은 오브젝트 테이블을 생성할 때 오브젝트 타입의 Attribute 하나를 오브젝트 테이블의 기본 키로 지정하는 예입니다.

**\[예 7] 오브젝트 테이블 생성 시 Attribute를 기본 키로 지정**

```
CREATE TABLE customer_type_tab2 of customer_type2 
    (custno PRIMARY KEY);
```

테이블이 컬럼 오브젝트를 가질 때에도 해당 오브젝트의 Attribute에 제약 조건을 정의할 수 있는데, 이 때는 점(.) 표기법으로 정의할 수 있습니다.

**\[예 8] 컬럼 오브젝트의 제약 조건 설정**

```
CREATE TABLE customer3
    ( cust_obj customer_type2, 
    status VARCHAR(1), 
    CONSTRAINT cust_check_cons
    CHECK (cust_obj.custno IS NOT NULL));
```

#### **인덱스**

인덱스 컬럼이 될 수 있는 조건은 제약 조건을 정의할 수 있는 컬럼의 조건과 동일합니다. 오브젝트 타입의 포함 관계 트리에서 맨 아래에 존재하는 Attribute만을 인덱스 컬럼으로 지정할 수 있습니다. 컬럼 오브젝트의 경우 점(.) 표기법으로 정의할 수 있습니다.

**\[예 9] 컬럼 오브젝트의 인덱스 생성**

```
CREATE INDEX cust_idx_1 ON customer3 (cust_obj.custno);
```

함수 기반 인덱스를 생성하는 경우 함수의 반환 타입이 오브젝트 타입일 경우는 생성이 허용되지 않습니다.

#### **Attribute 이름의 대상 찾기**

테이블의 컬럼이 오브젝트 타입인 경우 이 오브젝트의 Attribute 값을 Select하는 경우 점(.) 표기법을 사용합니다. SELECT 문에서 점(.) 표기법을 사용할 때 한 가지 주의할 점은 오브젝트 컬럼에 대해 점(.) 표기법을 사용할 때 항상 테이블 별칭을 점(.) 표기법과 앞에 표기해 주어야 합니다.

**\[예 10] 테이블의 컬럼이 오브젝트 타입인 경우 Select**

```
-- 에러가 발생하는 문장(TBR-8026)
SELECT cust_obj.phone FROM customer3;

-- 올바른 문장
SELECT x.cust_obj.phone FROM customer3 x;
```

#### **VALUE(x) 표현식**

VALUE(x) 표현식은 SQL에서 오브젝트 테이블의 테이블 별칭을 인자로 받아 현재 행에 해당하는 행 오브젝트를 반환하는 표현식입니다.

**\[예 11] VALUE(x) 표현식**

```
INSERT INTO customer_type_tab2 values (1, 'David', '555-666-7777'); 

set serveroutput on
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;
/
```

위의 예처럼 오브젝트 테이블의 Attribute 값을 조회하는 것이 아니고 오브젝트의 멤버 메소드를 호출하는 경우에는 VALUE(x) 표현식이 필요합니다. VALUE(x) 표현식은 다음과 같이 UPDATE 문을 수행하는 경우 사용자 정의 생성자("[생성자 메소드](#undefined-14)" 참고)가 생성한 오브젝트로 오브젝트 테이블의 현재 오브젝트를 덮어쓰는 경우에도 사용할 수 있습니다.

**\[예 12] 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 함수 혹은 프러시저일 수 있으며 해당 오브젝트에 대해 수행할 연산을 명시합니다. 메소드는 멤버 메소드, 정적 메소드, 생성자 메소드, 그리고 오브젝트의 비교에 사용하는 MAP 메소드와 ORDER 메소드로 나뉩니다. 메소드의 종류별 정의 방법과 SELF 매개변수의 규칙은 "tbPSM 안내서"의 [오브젝트 타입](/tibero-manuals/7.2.6.manuals/tbpsm-guide/object-type.md)을 참고합니다. 본 절에서는 SQL 문장에서 메소드를 사용할 때 적용되는 규칙을 중심으로 설명합니다.

#### **멤버 메소드**

멤버 메소드는 오브젝트 표현식 다음에 점(.) 표기법을 사용하여 호출합니다. 점 앞에 오는 것은 해당 오브젝트의 값을 가질 수 있는 오브젝트 표현식이고, 점 다음에는 그 오브젝트의 오브젝트 타입에서 정의하고 있는 멤버 메소드의 이름을 명시합니다. SQL에서 멤버 메소드를 호출할 때는 메소드에 건네줄 매개변수가 없는 경우에도 다음과 같이 항상 괄호를 붙여주어야 합니다.

**\[예 13] 멤버 메소드 호출**

```
SELECT x.cust_obj.tostring() FROM customer2 x;
```

다음은 실행 결과입니다. 첫 번째 행의 컬럼 오브젝트는 NULL 오브젝트이므로 호출 결과가 NULL이 됩니다.

```
X.CUST_OBJ.TOSTRING()
--------------------------------------------------------------------------------

::

2 rows selected.
```

#### **오브젝트 테이블에서의 멤버 메소드 호출**

멤버 메소드의 첫 번째 매개변수로는 항상 대상 오브젝트의 값이 전달되는 SELF 매개변수가 존재하며, 다음 예의 area 메소드처럼 메소드를 정의할 때 직접 명시할 수도 있습니다. SELF 매개변수의 자세한 규칙은 "tbPSM 안내서"의 [오브젝트 타입](/tibero-manuals/7.2.6.manuals/tbpsm-guide/object-type.md)을 참고합니다.

**\[예 14] 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) 표현식으로도 가능합니다.

**\[예 15] 오브젝트 테이블에서의 멤버 메소드 호출**

```
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 메소드) 형태로 존재하는데, 하나의 오브젝트 타입에 대해서 이 둘 중 하나만을 정의할 수 있습니다. 두 메소드의 파라미터와 반환값 규칙은 "tbPSM 안내서"의 [오브젝트 타입](/tibero-manuals/7.2.6.manuals/tbpsm-guide/object-type.md)을 참고합니다.

* **MAP 메소드**\
  하나의 내장 타입 값을 반환하는 메소드입니다. 이 값을 기준으로 오브젝트를 비교하거나, 정렬하는 데 이용할 수 있습니다. 오브젝트 표현식에 대해 SQL에서 ORDER BY를 구사하면, 자동적으로 이 MAP 메소드가 각 오브젝트에 대해 호출됩니다.

다음은 비교 연산을 위해 해당 오브젝트 타입에 MAP 메소드를 정의하는 예입니다.

**\[예 16] 오브젝트 타입에 MAP 메소드 정의**

```
CREATE OR REPLACE TYPE rectangle_type2 AS OBJECT 
    ( x NUMBER,
    y NUMBER,
    MAP MEMBER FUNCTION area RETURN NUMBER);
/

CREATE OR REPLACE TYPE BODY rectangle_type2 AS 
    MAP MEMBER FUNCTION area RETURN NUMBER IS 
    BEGIN
        RETURN SELF.x * SELF.y; 
    END;
END;
/

CREATE TABLE rect_cmp (
    c1   rectangle_type2,
    c2   rectangle_type2
);
```

MAP 메소드가 정의되어 있을 때 위의 예처럼 컬럼 c1과 컬럼 c2가 해당 오브젝트 타입이라면 다음의 첫 번째 SQL은 실제로 두 번째 SQL과 같이 수행됩니다.

```
SELECT 1 FROM rect_cmp x WHERE x.c1 > x.c2;
```

```
SELECT 1 FROM rect_cmp x WHERE x.c1.area() > x.c2.area();
```

* **ORDER 메소드**\
  비교할 두 개의 오브젝트를 매개변수로 받아서 비교 결과를 반환하는 메소드입니다. 이 중 첫 번째 오브젝트는 SELF를 통해 전달되므로, SELF와 비교할 나머지 오브젝트만을 추가 매개변수로 전달하면 됩니다. ORDER 메소드는 비교 연산자를 통한 오브젝트의 비교에서는 자동적으로 호출되나, ORDER BY에서는 호출되지 않습니다.\
  \
  ORDER 메소드의 반환값은 음수, 0, 양수의 숫자형 값을 반환하여야 하며 이 값들은 각각 SELF 오브젝트가 비교하는 오브젝트보다 작거나 또는 같거나 또는 더 큼을 의미합니다.<br>

**\[예 17] 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;
/

CREATE TABLE t1 (
    c1   address_type,
    c2   address_type
);
```

만일 MAP 메소드도 ORDER 메소드도 존재하지 않는데 동등 비교(equal) 또는 비동등 비교(inequal) 연산을 수행할 경우 이 비교는 오브젝트 타입의 포함 관계 트리에서 맨 아래에 존재하는 Attribute(즉, 내장 타입 Attribute) 각각에 대해 비교를 수행하고, 그 결과들을 AND 연산(비동등 비교일 때 OR 연산)으로 묶은 것과 같은 것으로 간주되어 정상 수행됩니다. 즉, 만일 위의 address\_type에서 ORDER 메소드가 정의되지 않았다고 했을 때 다음의 첫 번째 SQL이 수행되면 이 SQL은 실제로 두 번째 SQL과 같이 수행됩니다.

**\[예 18] 메소드 비교**

```
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 매개변수가 존재하지 않습니다. 정적 메소드를 호출하기 위해서는 메소드 이름 앞에 점(.)을 사용하여 오브젝트 타입 이름을 선행합니다.

다음 예제에서 정의하는 REC\_TYPE 타입은 정적 메소드와 사용자 정의 생성자를 가지며, 이어지는 예제에서 사용합니다.

**\[예 19] 정적 메소드와 사용자 정의 생성자를 가지는 타입**

```
CREATE OR REPLACE TYPE REC_TYPE AS OBJECT (
    x NUMBER,
    y NUMBER,

    STATIC FUNCTION get_info RETURN VARCHAR2,

    CONSTRUCTOR FUNCTION REC_TYPE(side_length NUMBER) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY REC_TYPE AS 

    STATIC FUNCTION get_info RETURN VARCHAR2 IS
    BEGIN
        RETURN 'Type: REC_TYPE (Geometry Object)';
    END;

    CONSTRUCTOR FUNCTION REC_TYPE(side_length NUMBER) RETURN SELF AS RESULT IS
    BEGIN
        SELF.x := side_length;
        SELF.y := side_length;
        RETURN;
    END;
END;
/
```

**\[예 20] 정적 메소드 호출**

```
SELECT REC_TYPE.get_info() FROM DUAL;
```

다음은 실행 결과입니다.

```
REC_TYPE.GET_INFO()
--------------------------------------------------------------------------------
Type: REC_TYPE (Geometry Object)

1 row selected.
```

#### **생성자 메소드**

생성자 메소드는 수행의 결과로 해당 타입의 오브젝트를 반환하는 함수입니다. 이것은 미리 정의되어 있는 디폴트 생성자와 사용자가 정의하는 사용자 정의 생성자로 나눌 수 있습니다.

* **디폴트 생성자**\
  디폴트 생성자는 생성자의 매개변수로 해당 오브젝트 타입의 Attribute 값을 순서대로 명시하여 호출하는 생성자입니다.<br>
* **사용자 정의 생성자 메소드**\
  사용자 정의 생성자 메소드는 사용자가 해당 타입의 오브젝트 생성을 위해 오브젝트 타입 내에 직접 정의하는 메소드 함수입니다. 사용자 정의 생성자를 정의하는 방법은 "tbPSM 안내서"의 [오브젝트 타입](/tibero-manuals/7.2.6.manuals/tbpsm-guide/object-type.md)을 참고합니다.<br>

다음은 \[예 19]에서 정의한 REC\_TYPE 타입의 생성자를 SQL에서 호출하는 예입니다.

**\[예 21] 생성자 메소드 호출**

```
SELECT REC_TYPE(10, 5) FROM DUAL;

SELECT REC_TYPE(7) FROM DUAL;
```

다음은 실행 결과입니다. 첫 번째 문장은 Attribute 값을 순서대로 명시했으므로 디폴트 생성자가 호출되고, 두 번째 문장은 매개변수가 하나이므로 사용자 정의 생성자가 호출됩니다.

```
REC_TYPE(10,5)
--------------------------------------------------------------------------------
REC_TYPE(10, 5)

1 row selected.

REC_TYPE(7)
--------------------------------------------------------------------------------
REC_TYPE(7, 7)

1 row selected.
```

## 오브젝트의 동작

본 절에서는 Tibero 오브젝트의 실제 동작과 관련한 몇 가지 내용을 설명합니다.

### 오브젝트의 저장

오브젝트는 Attribute들의 집합으로 구성되며, 각각의 Attribute 역시 오브젝트가 될 수 있기 때문에(단, 순환 참조는 허용하지 않습니다) 오브젝트 타입을 정의하고 나면 이것은 오브젝트 간의 포함 관계를 나타내는 하나의 Tree로 표현이 가능해집니다. Tree에서 단말에 위치하는 Attribute는 오브젝트 타입 Attribute일 수 없으며 내장 타입을 가지는 Attribute가 됩니다.

오브젝트가 테이블에 저장될 때는 한 오브젝트가 하나의 값으로 합쳐져서 저장되지 않고 Tree에서 단말에 위치하는 내장 타입 Attribute들의 각 값으로 찢어져서 저장됩니다. 다시 말해, 오브젝트가 저장되어 있는 테이블의 하나의 컬럼이 오브젝트 자체에 대한 컬럼이 될 수는 없으며 NUMBER, VARCHAR2와 같은 내장 타입 컬럼과 배열 컬럼들로 구성된 여러 개의 컬럼들을 사용해 해당 오브젝트를 저장하게 됩니다.

테이블을 생성하는 경우 사용자가 명시한 컬럼의 타입이 오브젝트 타입일 경우 Tibero는 내부적으로 이런 내장 타입 컬럼들을 숨겨진 컬럼의 형태로 만들고 추가로 컬럼을 하나 더 추가하게 되는데, 이 컬럼(NULL 지시자 컬럼)에는 해당 오브젝트를 구성하는 오브젝트들 중(오브젝트의 Attribute 값 또한 임의의 오브젝트 타입의 오브젝트가 될 수 있으므로) 누가 NULL이고 누가 NULL이 아닌지에 대한 정보를 담게 됩니다. 그러나 단말 Attribute(내장 타입 Attribute)가 NULL인지 여부에 대한 정보는 NULL 지시자 컬럼에 들어가지 않고, 나머지 (내장 타입에 대한) 숨겨진 컬럼을 사용해 이 정보를 저장합니다.

오브젝트 테이블의 경우 오브젝트 테이블이 기반하는 오브젝트 타입을 구성하는 각각의 Attribute에 대해서 오브젝트 테이블의 컬럼을 생성하며 컬럼의 이름은 Attribute의 이름을 따라갑니다. 기반 오브젝트 타입의 특정 Attribute가 오브젝트 타입 Attribute일 경우 위에서 기술한 대로(즉, 일반 테이블에 사용자가 오브젝트 타입의 컬럼을 명시했을 때와 같이) 숨겨진 컬럼들이 내부적으로 추가됩니다.

오브젝트 테이블에서 VALUE(x) 표현식을 사용하여 오브젝트 테이블의 오브젝트에 접근할 경우 이 오브젝트는 오브젝트의 포함 관계 Tree 맨 아래에 있는 오브젝트부터 디폴트 생성자를 사용하여 오브젝트들을 생성하고, 마지막으로 가장 상위 단계의 오브젝트들 그리고 내장 타입 Attribute 값들을 모아 최종 오브젝트 타입의 디폴트 생성자를 호출해서 오브젝트 테이블의 오브젝트를 생성합니다.

{% hint style="info" %}
**참고**

이때 디폴트 생성자가 사용자에 의해 가려졌을 경우(매개변수의 타입과 개수, 순서가 디폴트 생성자와 동일한 생성자)라 하더라도 여전히 시스템에서 정의한 디폴트 생성자로 오브젝트를 생성합니다.
{% endhint %}

#### **오브젝트 테이블과 오브젝트 식별자(Object Identifier; OID)**

오브젝트 식별자를 이용해 오브젝트 테이블에 저장되는 오브젝트를 유일하게 식별할 수 있습니다. 오브젝트 식별자는 오브젝트 테이블을 생성하는 경우 자동생성형과 기본키 기반형 중 하나를 선택할 수가 있습니다.

* **자동생성형**\
  따로 지정하지 않으면 자동생성형 오브젝트 식별자가 오브젝트 테이블의 숨겨진 컬럼(OID 컬럼)으로서 할당이 됩니다. 오브젝트 테이블에 오브젝트를 하나 Insert할 때마다, 분산 환경까지 고려해서 전역적으로 유일한 16Bytes 값이 생성되며 이것이 OID 컬럼의 값으로서 저장이 됩니다. 이것은 CREATE TABLE을 수행할 때 OID 컬럼의 DEFAULT 값이 SYS\_GUID() 내장 함수로 선언된 것과 동일한 동작을 합니다.<br>
* **기본키 기반형**\
  오브젝트 테이블을 만들 때 기본키를 지정하면 해당 오브젝트 테이블의 오브젝트 식별자로서 사용할 수가 있습니다. CREATE TABLE 문에 OBJECT IDENTIFIER IS PRIMARY KEY 절을 추가하면서 생성하는 오브젝트 테이블은 자동생성형 OID 컬럼을 만들지 않고 기본키의 값을 오브젝트 식별자의 값으로 사용합니다. 기본키 기반형 오브젝트 식별자는 해당 테이블의 기본키 값을 기반으로 하고 있으므로, 유일성은 해당 오브젝트 테이블 내에서만 보장됩니다. 만일 기본키의 길이가 16Bytes보다 작은 경우 이것은 공간의 절약을 의미합니다.

#### **배열의 저장**

배열이 테이블의 컬럼으로 저장될 때는 실제로도 하나의 컬럼으로 저장됩니다. 배열 타입 값의 최대 길이는 구성요소 타입의 최대 길이를 배열 타입의 최대 구성요소 개수로 곱한 값에 약간의 오버헤드를 추가한 값입니다.

해당 배열 타입 값의 가능한 최대 길이가 VARCHAR2의 최대 길이를 넘을 경우 이 배열 컬럼을 가지는 테이블을 생성할 때 긴 길이의 배열 값을 저장할 수 있도록 하는 LOB 세그먼트도 같이 생성됩니다. 하지만 실제 값을 저장할 때는 LOB 세그먼트의 존재 유무와는 관계 없이 각각의 값별로 VARCHAR2의 최대 길이보다 작을 경우는 그대로 테이블에 저장되고, 그렇지 않을 경우는 LOB 세그먼트에 저장됩니다.

### 오브젝트 생성자

다음은 오브젝트 생성자의 주요 동작 방식에 대한 설명입니다.

* **생성자 가리기**\
  만일 사용자가 디폴트 생성자와 똑같이 생긴(매개변수의 타입과 개수, 순서가 디폴트 생성자와 똑같은) 생성자를 정의했을 경우 디폴트 생성자는 사용자에 의해 호출될 수 없으며 사용자가 정의한 생성자에 의해 가려집니다. 사용자 정의 생성자는 하위 타입으로 상속되지 않기 때문에 하위 타입에서 정의하는 생성자로 가려지지 않습니다.<br>
* **생성자 오버로딩**\
  생성자도 일반 타입 메소드와 마찬가지로 오버로딩(메소드 이름이 같지만 매개변수의 타입과 개수, 순서가 다른 메소드)할 수 있습니다. 이것은 특정 오브젝트 타입의 오브젝트를 생성하기 위한 생성자가 동시에 여러 개 존재할 수 있다는 의미입니다.<br>
* **생성자의 사용**\
  생성자는 표현식의 일종으로 일반 컬럼 및 함수가 사용될 수 있는 곳이라면 생성자도 사용이 가능합니다. SQL에서 생성자를 호출하기 위해서는 생성자의 인자가 없더라도 항상 괄호를 붙여 주어야 합니다. 생성자를 정의할 때는 SELF를 명시할 수 있으나, 호출할 때는 SELF에 해당하는 매개변수를 명시할 수 없습니다. CREATE TABLE 또는 ALTER TABLE의 DEFAULT 절 그리고 CHECK 제약 조건에는 사용자 정의 생성자가 올 수 없으며 디폴트 생성자만 올 수 있습니다.
