ヘッダーをスキップ
Oracle® Databaseオブジェクト・リレーショナル開発者ガイド
11gリリース2 (11.2)
E94920-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

8 Oracleオブジェクトの高度なトピック

このマニュアルの前の章では、Oracleオブジェクトで作業を開始するために必要なトピックについて説明しています。この章では、オブジェクト・リレーショナル技法を大規模なアプリケーションまたは複雑なスキーマに適用する場合について説明します。

内容は次のとおりです。

オブジェクトの記憶域

Oracleデータベースは、オブジェクト型の複合構造を、記憶域に対する単純な表構造に自動的にマップします。

関連する内容は次のとおりです。

リーフ・レベル属性

オブジェクト型はツリー構造に似ており、ブランチが属性を表します。それ自体がオブジェクトである属性は、それ自体の属性でサブブランチを発生させます。

最終的に、各ブランチの終わりは、組込み型(NUMBERVARCHAR2REFなど)またはコレクション型(VARRAY、ネストした表など)の属性になります。元のオブジェクト型のこのようなリーフ・レベル属性は、それぞれ表の列に格納されます。

コレクション型ではないリーフ・レベル属性は、オブジェクト型のリーフ・レベル・スカラー属性と呼ばれます。

次の内容は、「オブジェクトを表に格納する方法」のオブジェクト表およびリレーショナル表の説明に関連しています。

列にまたがって分割される行オブジェクト

オブジェクト表では、すべてのリーフ・レベル・スカラー属性またはREF属性に対するデータが、個々の列に格納されます。


注意:

VARRAYも、大きすぎないかぎり、列に格納されます。ネストした表型のリーフ・レベル属性は、オブジェクト表に対応付けられた個々の表に格納されます。これらの表は、オブジェクト表宣言の一部として宣言する必要があります。「VARRAYの内部レイアウト」および「ネストした表の内部レイアウト」を参照してください。

オブジェクト表にある行オブジェクトの属性を取り出したり、変更する場合、対応する操作が表の列で実行されます。行オブジェクト自体の値にアクセスすると、オブジェクト表の列を引数として使用し、その型のデフォルトのコンストラクタを起動して、オブジェクトのコピーを生成します。

システムによって生成されたオブジェクト識別子は、非表示列に格納されます。オブジェクト識別子を使用して、そのオブジェクトに対するREFを作成します。

列オブジェクトを持つ表の非表示列

表(リレーショナル表)がオブジェクト型の列とともに定義されている場合、オブジェクト型のリーフ・レベル属性に対する表に、非表示列が追加されます。オブジェクト型の各列には、その列オブジェクトのNULL情報(トップレベルのオブジェクトおよびネストしたオブジェクトのアトミックNULL)を格納するための非表示列があります。

代入可能な列およびオブジェクト表の非表示列

代入可能な列またはオブジェクト表には、その列のオブジェクト型の各属性に対してのみでなく、そのオブジェクト型のサブタイプに追加された各属性に対しても、非表示列があります。これらの列には、代入可能な列に挿入されたサブタイプのインスタンスに対する属性の値が格納されます。

型判別式の列およびNULLイメージ列以外に、次の列が例8-1で作成されるperson_typの代入可能な列に関連付けられます。

  • person_typの各属性の非表示列: idnonameおよびphone

  • person_typのサブタイプの属性の非表示列

したがって、student_typに対する属性dept_idmajorおよびpart_time_student_typに対する属性number_hoursperson_typの代入可能な列に関連付けられる場合があります。

サブタイプを作成する場合、サブタイプの新しい属性の非表示列が、その新しいサブタイプの祖先クラスの代入可能な列を含む表に自動的に追加されます。追加された非表示列は、表にレトロフィットして、新しい型のデータを格納できるようになります。なんらかの理由で、非表示列を追加できない場合は、そのサブタイプの作成はロールバックされます。

VALIDATEオプションとともにDROP TYPEを使用してサブタイプを削除すると、データを含まないサブタイプの固有の属性に対する非表示列は、自動的に削除されます。これらの列にデータが含まれる場合、エラーが発生します。

例8-1では、この章の後続の例に必要な型を作成します。

例8-1 型の作成および表への挿入

-- drop any of these objects created for Ex.7-10
CREATE TYPE person_typ AS OBJECT (
  idno           NUMBER,
  name           VARCHAR2(30),
  phone          VARCHAR2(20),
  MAP MEMBER FUNCTION get_idno RETURN NUMBER )
  NOT FINAL;
/
CREATE TYPE BODY person_typ AS
  MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
  BEGIN
    RETURN idno;
  END;
END;
/
CREATE TYPE student_typ UNDER person_typ (
    dept_id NUMBER,
    major VARCHAR2(30))
NOT FINAL;
/
CREATE TYPE part_time_student_typ UNDER student_typ (
  number_hours NUMBER);
/
CREATE TYPE employee_typ UNDER person_typ (
    emp_id NUMBER, 
    mgr VARCHAR2(30));
/
CREATE TABLE person_obj_table OF person_typ;  // an object table
INSERT INTO person_obj_table 
  VALUES (person_typ(12, 'Bob Jones', '650-555-0130'));
INSERT INTO person_obj_table 
  VALUES (student_typ(51, 'Joe Lane', '1-650-555-0140', 12, 'HISTORY'));
INSERT INTO person_obj_table 
  VALUES (part_time_student_typ(52, 'Kim Patel', '1-650-555-0135', 14,
          'PHYSICS', 20));

代入可能な列は、非表示の型判別式の列に関連付けられます。非表示列には、型IDと呼ばれる識別子があり、この識別子によって、代入可能な列中の各オブジェクトのうち、最も具体的な型が識別されます。通常、型ID(RAW)は1バイトですが、大きな階層の場合は最大4バイトまでとなります。

指定されたオブジェクト・インスタンスの型IDは、ファンクションSYS_TYPEIDを使用して特定できます。

例8-2では、例8-1で作成される代入可能なオブジェクト表に格納されるオブジェクト・インスタンスの型IDを取り出します。

例8-2 表に格納されるオブジェクトの型IDの問合せ

-- Requires Ex. 8-1
SELECT name, SYS_TYPEID(VALUE(p)) typeid 
  FROM person_obj_table p;

NAME TYPEID
------------------------------ ---------------------------
Bob Jones 01
Joe Lane 02
Kim Patel 03

カタログ・ビューのUSER_TYPESDBA_TYPESおよびALL_TYPESには、各型に対する型ID値を与えるTYPEID列(非表示ではない)があります。この列に対して結合を実行して、型判別式の列にある型IDに対応する型名を取得できます。


関連項目:

SYS_TYPEID、型IDおよび型判別式の列の詳細は、「SYS_TYPEID」を参照してください。

REFの記憶域

データベースが行オブジェクトに対してREFを作成する場合、その作成されるREFは、オブジェクト識別子(OID)、オブジェクト表のいくつかのメタデータ、およびROWID (オプション)で構成されます。

REF型の列にあるREFのサイズは、次のその列に対応付けられた記憶域要件に依存します。

  • 列がREF WITH ROWIDとして宣言されている場合、ROWIDREF列に格納されます。ROWIDのヒントは、制約付きREF列にあるオブジェクト参照では無視されます。

  • 列がSCOPE句を使用してREFとして宣言されている場合、オブジェクト表のメタデータおよびROWIDの省略によって、その列は少なくなります。有効範囲付きREFの長さは、16バイトです。

オブジェクト識別子が主キー・ベースの場合、主キーを導出する列の数に基づいて、主キーの値を格納するための1つ以上の内部列が作成されます。


注意:

オブジェクト識別子が主キーから導出される行オブジェクトをREF列が参照する場合、このREF列を、主キー・ベースREFまたはpkREFといいます。pkREFを含む列は、有効範囲付きであるかまたは参照制約が指定されている必要があります。

ネストした表の内部レイアウト

ネストした表の行は、別の記憶表に格納されます。ネストした表には、列ごとに1つの記憶表が対応付けられています。記憶表は、その列にあるすべてのネストした表に対するすべての要素を保持しています。記憶表には、システム生成の値を持つ非表示のNESTED_TABLE_ID列があり、この値によって、Oracle Databaseでは、ネストした表の要素が適切な行にマップされます。

記憶表を索引構成表にすることによって、コレクション全体を取り出す問合せを高速化できます。ORGANIZATION INDEX句をSTORE AS句の中に挿入します。

「ネストした表の記憶域」を参照してください。

ネストした表型は、オブジェクトまたはスカラーを含むことができます。

  • 要素がオブジェクトである場合、記憶表はオブジェクト表のようになります。つまり、そのオブジェクト型のトップレベルの属性が記憶表の列となります。ただし、ネストした表の行にはオブジェクト識別子列がないため、ネストした表のオブジェクトに対してREFは作成できません。

  • 要素がスカラーである場合、記憶表には、スカラー値を含むCOLUMN_VALUEという単一の列が含まれます。

VARRAYの内部レイアウト

VARRAYのすべての要素は、単一の列に格納されます。配列のサイズに基づいて、インラインまたはBLOBに格納されます。詳細は、「VARRAYの記憶域上の考慮点」を参照してください。

型IDまたは属性の索引作成

この項では、型IDおよび属性での索引の使用方法を説明します。

この項の内容は次のとおりです。

型判別式の列の索引付け

SYS_TYPEIDファンクションを使用して、代入可能な列の非表示の型判別式の列に索引を作成できます。型判別式の列には、型IDがあり、この識別子によって、代入可能な列中の各オブジェクト・インスタンスのうち、最も具体的な型が識別されます。この情報は、IS OF述語を使用して型に基づいてフィルタにかける問合せの評価に使用されるものですが、SYS_TYPEIDファンクションを使用して独自の目的で型IDにアクセスすることも可能です。

一般に、型判別式の列には、わずかな数の型IDのみが格納されています。関連のある型階層に含まれている型の数を超えることはありません。この列はカーディナリティが低いので、ビットマップ索引の作成に適しています。

たとえば、次の文では、表contactsの代入可能なcontact列の基礎となる型判別式の列のビットマップ索引を作成します。ファンクションSYS_TYPEIDは、型判別式の列を参照します。

例8-3 代入可能な列のビットマップ索引の作成

-- Requires Ex. 8-1
CREATE TABLE contacts (
  contact         person_typ,
  contact_date    DATE );
INSERT INTO contacts VALUES (
  person_typ (65,'Vrinda Mills', '1-650-555-0125'),'24 Jun 2003' );
INSERT INTO contacts VALUES (
  person_typ (12, 'Bob Jones', '650-555-0130'),'24 Jun 2003' );
INSERT INTO contacts VALUES (
  student_typ(51, 'Joe Lane', '1-650-555-0140', 12, 'HISTORY'),'24 Jun 2003' );
INSERT INTO contacts VALUES ( part_time_student_typ(52, 'Kim Patel', '1-650-555-0135', 14, 'PHYSICS', 20),'24 Jun 2003' ); 
CREATE BITMAP INDEX typeid_idx ON contacts (SYS_TYPEID(contact));

代入可能なサブタイプの索引付け

代入可能な列内に格納できる任意の型の属性に対して索引を作成できます。サブタイプの属性は、TREATファンクションを使用して求めるサブタイプ(およびそのサブタイプ)以外の型をフィルタにかけて排除することによってCREATE INDEX文で参照できます。その後、ドット表記によって、希望の属性を指定します。

たとえば、次の文では、contacts表にある、すべての学生のmajor属性に対する索引が作成されます。contact列の宣言された型はperson_typで、student_typがそのサブタイプであるため、この列にはperson_typstudent_typのインスタンスおよびいずれかのサブタイプを格納できます。

例8-4 すべての学生の属性に対する索引の作成

-- Requires Ex.8-1- and 8-3
CREATE INDEX major1_idx ON contacts 
  (TREAT(contact AS student_typ).major);

student_typは、最初にmajor属性を定義しました。person_typスーパータイプにはこの型はありません。したがって、major属性に対する非表示列のすべての値は、個人の型student_typまたはparttimestudent_typ (student_typサブタイプ)に対する値です。つまり、非表示列の値は、学生のサブタイプも含めてすべての学生のmajorの値のTREAT式によって戻される値と同一であることを意味しています。つまり、非表示列も、TREAT式もともに、学生については専攻を、学生以外についてはNULLをリストします。このことを利用して、非表示列に対する索引major1_idxが、通常のBツリー索引として作成されます。

非表示列の値が、前述のように、TREAT式によって戻される値と同一になるのは、TREATファンクションのターゲットとして指定された型(student_typ)が最初にそのmajor属性を定義した型である場合にかぎります。TREATファンクションのターゲットが、次の例のように、単にその属性を継承するサブタイプである場合は、TREAT式は、サブタイプ(定時制の学生)に対してはNULL以外のmajor値を戻しますが、スーパータイプ(その他の学生)に対しては非NULLは戻しません。

CREATE INDEX major2_idx ON contacts 
  (TREAT(contact AS part_time_student_typ).major);

この場合、非表示列にmajorの値として格納されている値は、TREAT式の結果とは異なっている場合があります。したがって、通常のBツリー索引を基礎となる列に対して作成することはできません。したがって、データベースでは、TREAT式は他のすべてのファンクション・ベースの式と同様に処理され、索引を、結果に対するファンクション索引として作成する試みが行われます。

次の例では、前述の例と同様に、定時制の学生のmajor属性に対してファンクション索引を作成しますが、この例では、majorの非表示列は、代入可能なオブジェクト表person_obj_tableに対応付けられています。

CREATE INDEX major3_idx ON person_obj_table p 
  (TREAT(VALUE(p) AS part_time_student_typ).major);

型進化

型進化は、オブジェクト型を変更するプロセスです。オブジェクト型は、次の方法で変更できます。

  • 属性の追加および削除

  • メソッドの追加および削除

  • 長さ、精度または位取りを引き上げるための数値属性の修正

  • 文字長を長くするための可変長文字属性の修正

  • 型のFINALおよびINSTANTIABLEプロパティの変更

  • VARRAYの制限およびサイズの変更

  • コレクション要素の長さ、精度およびスケールの変更

型を変更すると、その型を参照する項目にも影響します。たとえば、新しい属性を型に追加する場合、その新しい属性を追加できるように、その型の列にあるデータを提示する必要があります。

この項の内容は次のとおりです。

型進化および依存スキーマ・オブジェクト

型の依存スキーマ・オブジェクトは、型を直接的または間接的に参照し、その型に加えられた変更に影響されるオブジェクトです。

型は、次の依存スキーマ・オブジェクトを持つことができます。表、型またはサブタイプ、プロシージャ、ファンクション、パッケージ、トリガーなどのプログラム・ユニット(PL/SQLブロック)、索引タイプ、ビュー(オブジェクト・ビューを含む)、ファンクション索引、演算子。

依存スキーマ・オブジェクトが型の変更によってどのような影響を受けるかは、オブジェクトによって、また、変更の性質によって異なります。

  • 依存プログラム・ユニット、ビュー、演算子および索引タイプは、型が変更されると、無効としてマークされます。これらの無効となったスキーマ・オブジェクトのいずれかが次回参照されると、新しい型の定義を使用して再検証されます。オブジェクトの再コンパイルが成功すると、そのオブジェクトは有効となり、再度使用できるようになります。

  • 型の変更によっては、依存ファンクション索引が削除または無効化され、再構築が必要です。

  • 依存表には、属性の型に応じて型に加えられた各属性に対して表に1つ以上の内部列が追加されます。新しい属性が追加される際は、NULL値が設定されます。削除された各属性に対応付けられている列は削除されます。変更された各属性に対応付けられた長さ、精度またはスケールも、変更内容に対応して変更されます。

これらの変更は、主に表のメタデータの更新を含み、迅速に実行できます。さらに、このような表データは、「データを更新するオプション」で説明するように、型の新しいバージョンの形式に合せた更新も必要です。

データを更新するオプション

更新は、データの量によっては時間がかかる場合があるため、ALTER TYPEコマンドにオプションが用意されています。このオプションによって、すべての依存表データを即時変換するか、元の形式のままにしておいて、更新のたびに少しずつ変換するかを選択できます。

ALTER TYPECASCADEオプションは、型の変更を依存型および依存表に伝播します。「型進化に使用するALTER TYPE文」を参照してください。CASCADE自体に、伝播の一環として表データを新しい型形式に変換するかどうかを選択できる次のオプションがあります。

  • INCLUDING TABLE DATA: データを変換します(デフォルト)

  • NOT INCLUDING TABLE DATA : データを変換しません

デフォルトでは、CASCADEオプションはデータを変換します。いずれの場合も、表データは常に最新バージョンの型の形式で戻されます。表データが以前の型バージョンの形式で保存されている場合は、データが実際に保存されている形式はデータが再書込みされないかぎり変更されないにしても、そのデータは、戻される前に最新バージョンの形式に変換されます。

最新の型の定義は、システム・ビューUSER_SOURCEから取り出せます。USER_TYPE_VERSIONSビューで、ある型のすべてのバージョンの定義を参照できます。


関連項目:

型の定義および型本体のコンパイルの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。


型への構造的な変更の影響

型に対する構造的な変更が依存データに影響し、データの変換を必要とします。これは、ある型のメソッドの定義や動作(実装)に限定された変更には適用されません。

型に対する次の変更は構造的変更です。

  • 属性の追加または削除

  • 属性の長さ、精度、スケールの変更

  • FINALからNOT FINALに(またはその逆に)型のファイナリティを変更します

このような変更の結果、変更された型およびそのすべての依存型のバージョンが新しいバージョンになり、新しいバージョンへの変更のプロセスの一環として、依存表の内部列が追加、削除または変更されます。

これらのいずれかの変更を、依存型または依存表を持つ型に対して実行すると、変更を伝播した影響は、メタデータのみでなく、データ記憶域の構成にも影響し、データの変換を必要とします。

データの変換以外にも、変更すべき項目がある場合があります。たとえば、新しい属性が型に追加されて、その型が、その型のコンストラクタをコールする場合、型本体の各コンストラクタは、新しい属性に対する値を指定するように修正する必要があります。同様に、新しいメソッドが追加される場合は、型本体を置換して、新しいメソッドの実装を追加する必要があります。型本体は、CREATE OR REPLACE TYPE BODY文を使用して変更できます。

属性の追加および削除による型の変更

例8-5に、ある属性を追加し、別の属性を削除することによってperson_typに単純な変更を加える方法を示します。CASCADEキーワードは、型の変更を依存型および依存表に伝播しますが、NOT INCLUDING TABLE DATA句によって関連するデータの変換が阻止されています。

例8-5 属性の追加および削除によるオブジェクト型の変更

-- Drop person_typ and person_obj_table if they exist
CREATE TYPE person_typ AS OBJECT (
  idno           NUMBER,
  name           VARCHAR2(30),
  phone          VARCHAR2(20));
/
CREATE TABLE person_obj_table OF person_typ;

INSERT INTO person_obj_table 
  VALUES (person_typ(12, 'Bob Jones', '650-555-0130'));

SELECT value(p) FROM person_obj_table p;

VALUE(P)(IDNO, NAME, PHONE)
--------------------------------------------
PERSON_TYP(12, 'Bob Jones', '650-555-0130')

次のように電子メール属性を追加し、電話属性を削除できます。

ALTER TYPE person_typ
  ADD ATTRIBUTE (email VARCHAR2(80)), 
  DROP ATTRIBUTE phone CASCADE NOT INCLUDING TABLE DATA;

次に、型の変更に対応するために切断して再接続します。

connect oe/oe;
connect hr/hr;
ALTER SESSION SET PLSQL_WARNINGS = 'enable:all';
-- The data of table person_obj_table has not been converted yet, but
-- when the data is retrieved, Oracle returns the data based on
-- the latest type version. The new attribute is initialized to NULL.
SELECT value(p) FROM person_obj_table p;

VALUE(P)(IDNO, NAME, EMAIL)
---------------------------------
PERSON_TYP(12, 'Bob Jones', NULL)

SELECT文では、列データが最新の型バージョンに変換されている可能性があるとしても、変換されたデータが列に再度書き込まれることはありません。ある表の特定のユーザー定義型の列が頻繁に取り出される場合、データ変換が重複して行われないようにするため、そのデータを最新の型バージョンに変換することを検討してください。変換は、列にオブジェクトやネストした表列より変換に必要な時間が通常長くなるVARRAY属性が含まれている場合、特に大きな効果があります。

前のコードと関連していない次のコード・スニペットに示すように、UPDATE文を発行して列をそれ自体に設定し、データの列を変換できます。

UPDATE dept_tab SET emp_array_col = emp_array_col;

ある表内のすべての列を、UPGRADE INCLUDING DATAとともにALTER TABLEを使用して変換できます。次に例を示します。

ALTER TYPE person_typ ADD ATTRIBUTE (photo BLOB)
  CASCADE NOT INCLUDING TABLE DATA;
ALTER TABLE person_obj_table UPGRADE INCLUDING DATA;

ALTER TABLE行は、リストされた表のみを変換します。CASCADEオプションは、他の表または依存オブジェクトが変換されないようにします。

ネストした表属性の追加による型の変更

この項では、ネストした表に含まれているオブジェクト型にネストした表属性を追加する型に複雑な変更を加える手順を説明します。

例8-6は、例8-7で変更される初期スキーマを示します。

例8-6 初期スキーマ

-- Drop existing person_typ, department_type, people_typ objects or tables
CREATE TYPE person_typ AS OBJECT (
  idno           NUMBER,
  name           VARCHAR2(30),
  phone          VARCHAR2(20));
/
-- creating a nested table type
CREATE TYPE people_typ AS TABLE OF person_typ;/
CREATE TYPE department_typ AS OBJECT (
  manager    person_typ,
  employee   people_typ);  // a nested table/
CREATE TABLE department OF department_typ
  NESTED TABLE employee STORE AS employee_store_nt;

例8-7は、新しいオブジェクトtasks_typおよびそれを保持するネストした表の型tasks_nttabの作成から開始されます。

属性としてネストした表tasksをネストした表people_typにすでに含まれているオブジェクト型person_typに追加するには、例8-7および他のプログラムの両方で次の手順が必要です。

  1. ALTER TYPE..INVALIDATE文を発行して、型person_typを変更します。この文では、時間を節約するために型および表のチェックをすべて迂回して、依存オブジェクトを無効にします。表のデータには、有効化されるまでアクセスできません。

    ALTER TYPE文には、ネストした表tasksを追加するADD ATTRIBUTEが含まれます。

    UPGRADE.. STORE AS句は、影響を受けるネストした表をアップグレードし、新規の記憶表の名前を指定します。

    例8-7 ネストした表属性の追加によるオブジェクト型の変更

    -- Requires Ex. 8-6
    CREATE TYPE tasks_typ AS OBJECT (
      priority       VARCHAR2(2),
      description    VARCHAR2(30));
    /
    
    CREATE TYPE tasks_nttab AS TABLE OF tasks_typ;
    /
    
    ALTER TYPE person_typ ADD ATTRIBUTE tasks tasks_nttab
      INVALIDATE;
    
    -- Propagate the change to employee_store_nt
    -- Specify a storage name for the new nested table
    ALTER TABLE employee_store_nt
      UPGRADE NESTED TABLE tasks STORE AS tasks_nt;
    
  2. 必要な場合はperson_typに対するCREATE OR REPLACE TYPE BODYを使用して、対応する型本体を更新して、新しい型定義に更新します。

  3. 依存表を最新の型バージョンにアップグレードし、表データを変換します。これにより、表が検証され、データ・アクセスが再度許可されます。

    ALTER TABLE department UPGRADE INCLUDING DATA;
    
  4. 必要に応じて、PL/SQL依存プログラム・ユニットを変更して、型に加えられた変更に対応します。

  5. アプリケーションがC言語で書かれているか、Javaで書かれているかによって、OTTまたはJPublisherを使用して、新しいヘッダー・ファイルを生成します。

    スーパータイプに新しい属性を追加すると、サブタイプの属性が新しい属性を継承するために、そのすべてのサブタイプの属性数が増大する可能性があります。継承された属性は、常に、宣言された(ローカルに定義された)属性に先行するので、新しい属性をスーパータイプに追加すると、各サブタイプのすべての宣言された属性の順序が1つずつ再帰的に増加されます。変更された型のマッピングを更新して、新しい属性を追加する必要があります。Oracle Type Translator (OTT)およびJPublisherがこれを行います。別のツールを使用する場合は、型のヘッダーが、サーバーでの型の定義と適切に同期されることを確認する必要があります。この同期が確実に行われない場合は、結果として予期しない動作が発生する可能性があります。

  6. 必要に応じてアプリケーション・コードを修正し、アプリケーションを再作成します。

変更された型の妥当性チェック

ALTER TYPE文の実行の際に、最初に、要求された型の変更について、構文上およびセマンティクス上の妥当性がチェックされます。CREATE TYPE文についても同様の妥当性チェックおよび追加の妥当性チェックが実行されます。ターゲットの型の新しい仕様またはその依存型のいずれかについて型の妥当性が確認されない場合は、ALTER TYPE文は異常終了します。この場合は、新しい型バージョンは作成されず、すべての依存オブジェクトが変更されないままになります。

依存表が存在する場合は、さらにチェックが行われて、表および索引に関連する制約が遵守されているかが確認されます。たとえば、削除の対象となっている属性が、パーティション化キーで使用されていないかが確認されます。ここでも、ALTER TYPE文について、表に関連する制約のチェックが失敗すると、型の変更は異常終了し、その型の新しいバージョンは作成されません。

単一のALTER TYPE文で複数の属性を追加する場合、指定された順序で実行されます。1つのALTER TYPE文で複数の型の変更を指定することはできますが、属性名およびメソッド・シグネチャは1回のみの指定となります。たとえば、単一の文で同じ属性の追加と変更を行うことはできません。

次の項では、次の型の変更に関するその他の注意事項について説明します。

属性の削除

  • ルート型に由来するすべての属性を削除することはできません。かわりに、型を削除する必要があります。サブタイプのすべての属性はスーパータイプから継承されるため、サブタイプからすべての属性を削除しても、その属性のカウントは0 (ゼロ)にはなりません。サブタイプでローカルに宣言された属性を削除することは許可されます。

  • ターゲットの型でローカルに宣言された型のみを削除できます。継承された属性を、サブタイプから削除することはできません。属性がローカルに宣言された場所でその型からその属性を削除してください。

  • 表パーティションの一部である属性または表のサブパーティション・キーの削除はできません。

  • オブジェクト表またはIOTの主キーOIDの属性の削除はできません。

  • 属性が削除されると、削除された属性に対応する列は削除されます。

  • 属性を削除すると、索引、統計、制約、および属性を参照する参照整合性制約が削除されます。

属性の型の長さ、精度、スケールの変更

  • 依存表のファンクション索引、クラスタ・キーまたはドメイン索引で参照される属性の長さは拡張できません。

  • 属性の長さ、精度、スケールを縮小できません。

メソッドの削除

  • メソッドは、そのメソッドの定義(または再定義)が行われた型からのみ削除できます。継承されたメソッドをサブタイプから削除することはできません。また、再定義したメソッドをスーパータイプから削除することもできません。

  • メソッドが再定義されていない場合、CASCADEオプションを使用してそのメソッドを削除すると、ターゲットの型に由来するメソッドおよびすべてのサブタイプが削除されます。一方、メソッドがサブタイプで再定義されている場合は、CASCADEは実行されないで、ロールバックされます。CASCADEが実行されるためには、メソッドを定義しているサブタイプから再定義されたメソッドを削除して、その後、スーパータイプからメソッドを削除します。

    USER_DEPENDENCIES表に、型も含めて、与えられた型に依存するすべてのスキーマ・オブジェクトがあります。また、DBMS_UTILITY.GET_DEPENDENCYユーティリティを実行して、型の依存関係を検索できます。

  • INVALIDATEオプションを使用して、再定義されたメソッドを削除できますが、サブタイプの再定義されたバージョンは、依然として手動で削除する必要があります。サブタイプは、再定義されたバージョンを削除するように明示的に変更されないかぎり、無効な状態のままです。それまでは、妥当性チェックのためにサブタイプを再コンパイルしようとすると、「メソッドは上書きしません。」というエラーが発生します。

    CASCADEとは異なり、INVALIDATEは、型および表のすべてのチェックを迂回して、その型に依存するすべてのスキーマ・オブジェクトを無効とします。それらのオブジェクトは、次回のアクセス時に再検証されます。このオプションは、CASCADEを使用するより高速に処理されますが、依存型および依存表の再検証時に問題が発生しないことが確認されている必要があります。表が無効な場合は、表データにはアクセスできません。表の妥当性が検証できない場合は、そのデータはアクセス不可のままとなります。

    「型の変更の妥当性チェックに失敗した場合」を参照してください。

INSTANTIABLEプロパティの変更

  • その型に表依存オブジェクトがない場合にかぎり、オブジェクト型をINSTANTIABLEからNOT INSTANTIABLEへ変更できます。

  • オブジェクト型のNOT INSTANTIABLEからINSTANTIABLEへの変更は任意の時点で実行できます。このように変更した場合、表には影響しません。

FINALプロパティの変更

  • ターゲットの型にサブタイプがない場合にかぎり、オブジェクト型をNOT FINALからFINALへ変更できます。

  • オブジェクト型をFINALからNOT FINAL、またはその逆に変更する場合は、CASCADEを使用して依存列内および依存表内のデータを即時変換する必要があります。CASCADEオプションNOT INCLUDING TABLE DATAを使用して、データを遅延させることはできません。

    • NOT FINALからFINALへは、CASCADE INCLUDING TABLE DATAを使用する必要があります。

    • FINALからNOT FINALへは、CASCADE INCLUDING TABLE DATAまたはCASCADE CONVERT TO SUBSTITUTABLEのいずれかを使用できます。

      FINALからNOT FINALに型を変更する場合、変更した型の新規サブタイプを既存の列および表に挿入するかどうかに基づいて、CASCADEオプションを選択します。

    デフォルトでは、型をFINALからNOT FINALに変更することで、代入可能な新しい表およびその型の列を作成できますが、その型の既存の列(またはオブジェクト表)が自動的に代入可能になることはありません。実際、その逆の動作が行われます。その型の既存の列および表はNOT SUBSTITUTABLE AT ALL LEVELSとマークされます。これらの列の埋込み属性が代入可能な場合は、エラーが生成されます。変更された型の新しいサブタイプは、これらの既存の列および表には挿入できません。

    既存の型の列および表を代入可能にするようオブジェクト型をNOT FINALに変更する場合(NOT SUBSTITUTABLEとマークされていないことを前提)は、CASCADEオプションCONVERT TO SUBSTITUTABLEを使用します。

    例8-8は、オプションCONVERT TO SUBSTITUTABLEを含むCASCADEの使用を示します。

    例8-8 FINALからNOT FINALへの型の変換

    CREATE TYPE shape AS OBJECT (
        name VARCHAR2(30),
        area NUMBER)
        FINAL;/
    ALTER TYPE shape NOT FINAL CASCADE CONVERT TO SUBSTITUTABLE;
    

    このCASCADEオプションにより既存の列がSUBSTITUTABLE AT ALL LEVELSとマークされ、列に格納されたインスタンスの型ID用に新しい非表示列が追加されます。その後、変更された型のサブタイプ・インスタンスを列に格納できます。

型の変更の妥当性チェックに失敗した場合

ALTER TYPE文のINVALIDATEオプションを使用して、依存オブジェクトに加えた型の変更を伝播することなく型の変更ができます。この場合、依存型および依存表の妥当性チェックは行われません。つまり、型の変更によるすべての影響が妥当であることを確認しません。かわりに、すべての依存スキーマ・オブジェクトに無効のマークが付けられます。これらのオブジェクト(型や表など)は、次回の参照時に再検証されます。型の再検証ができない場合、その型は無効のままとなり、そのような型を参照する表も、問題が修正されるまではアクセス不可となります。

表が妥当性チェックに失敗するのは、次のような理由です。型に新しい属性を追加してその表内の一部の列が、最大1000を超えた場合またはある表のパーティション化キーまたはクラスタ化キーとして使用されている属性が型から削除された場合。

型の再検証は、ALTER TYPE COMPILE文を発行すると強制的に実行できます。無効な表の再検証を強制的に実行するには、ユーザーは、ALTER TABLE UPGRADE文を発行して、データを最新の型バージョンに変更するかどうかを指定できます。


注意:

表の参照時にトリガーされた表の妥当性チェックにおいて、表データは常に最新の型バージョンになるよう更新されます。データの変換を延期するオプションはありません。

表を最新の型バージョンに変換できない場合、その表に対するINSERT文、UPDATE文およびDELETE文は使用できず、その表データにはアクセスできなくなります。その表に対して次のDDLは実行できますが、無効な表を参照する他のすべての文は、その表の妥当性が検証されるまで使用できません。

  • DROP TABLE

  • TRUNCATE TABLE

ある表の%ROWTYPEまたはある列の%TYPE、あるいはある表にある属性を使用して定義された変数を含むすべてのPL/SQLプログラムは、最新の型バージョンに基づいてコンパイルされます。その表の再検証が失敗すると、その表を参照する任意のプログラム・ユニットのコンパイルも失敗します。

型進化に使用するALTER TYPE文

表8-1に、型の属性またはメソッド定義を変更するために使用するALTER TYPEおよびALTER TYPE...CASCADE文の一部の重要なオプションを示します。

表8-1 型進化に使用するALTER TYPEオプション

オプション 説明

INVALIDATE

すべての依存オブジェクトを無効とします。このオプションを使用して、型および表のすべてのチェックを迂回し、時間を節約します。

このオプションは、依存型および依存表の再検証において問題が発生しないことが確実な場合に使用してください。表の妥当性が検証されるまでは表データにはアクセスできません。表の妥当性チェックができない場合は、そのデータはアクセス不可のままになります。

CASCADE

型の変更を依存型および依存表に伝播します。この文は、FORCEオプションが指定されていないかぎり、依存型または依存表にエラーが検出されると異常終了します。

他のオプションなしにCASCADEが指定されていると、CASCADEに対してINCLUDING TABLE DATAオプションが暗黙的に指定され、すべての表データが最新の型バージョンに変換されます。

INCLUDING TABLE DATA (CASCADEのオプション)

すべてのユーザー定義列に格納されているデータを、列の型の最新バージョンに変換します。

列の型に追加された新しい属性ごとに、新しい属性がデータに追加され、NULLに初期化されます。参照される型から削除された属性ごとに、対応する属性データが表から削除されます。表のデータが格納されているすべての表領域は、読取り/書込みモードにする必要があります。そうしないと、この文の処理は失敗します。

NOT INCLUDING TABLE DATA (CASCADEのオプション)

列データをそのまま維持し、型バージョンを変更しません。属性が表が参照する型から削除されても、削除された属性の対応する列は表から削除されません。ただし、その列のメタデータが未使用とマークされるのみです。削除された属性が列外(たとえば、VARRAY属性、LOB属性、またはネストした表属性)に格納されている場合は、その列外のデータは削除されません。(使用されない列は、後で、ALTER TABLE DROP UNUSED COLUMNS文を使用して削除できます。)

このオプションは、数多くの大きな表があり、1つのトランザクションでそのすべてを変換すると、ロールバック・セグメントが不足する可能性がある場合に使用します。このオプションを使用して、後で、各依存表のデータを、別個のトランザクションで変換できます(ALTER TABLE UPGRADE INCLUDING DATA文を使用します)。

このオプションを指定すると、表のデータは、以前の型バージョンの形式のまま維持されるので、表の更新が高速化されます。ただし、この表からデータを選択するには、その列に格納されているイメージを最新の型バージョンに変換する必要があります。この操作は、後続のSELECT文が実行される際のパフォーマンスに影響を及ぼす可能性があります。

このオプションは、表のメタデータの更新のみを必要とするため、文を正常に実行するためにすべての表領域の読取り/書込みモードでのオンライン化が必要なわけではありません。

FORCE (CASCADEのオプション)

システムに、依存表および索引からのエラーを無視させます。エラーについては、後で問合せができるように、指定された例外表にログが作成されます。一部の表でエラーが発生した場合、依存表にアクセスできなくなる可能性があるので、このオプションは慎重に使用してください。

CONVERT TO SUBSTITUTABLE (CASCADEのオプション)

型をFINALからNOT FINALに変更する場合に使用するオプションで、すべてのユーザー定義列に格納されているデータを、最新バージョンの列の型に変換し、型の新しく作成されたサブタイプがSUBSTITUTABLE AT ALL LEVELS型の既存の列およびオブジェクト表に格納できるように、これらの列および表をマークします。

このオプションを指定せずに、型をNOT FINALに変更した場合、その型の既存の列および表はNOT SUBSTITUTABLE AT ALL LEVELSとマークされ、その型の新しいサブタイプをこれらの列および表に格納できません。型が変更された後に作成される列および表にのみこれらのサブタイプを格納できます。



関連項目:

ALTER TYPEオプションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

型進化に使用するALTER TABLE文

ALTER TABLEを使用して、参照される型の最新バージョンに表データを変換できます。例は、「ネストした表属性の追加による型の変更」を参照してください。INCLUDING DATAオプションの詳細は、表8-1を参照してください。


関連項目:

ALTER TABLEオプションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

システム定義およびユーザー定義コンストラクタ

この項では、属性値コンストラクタとも呼ばれるシステム定義コンストラクタおよびユーザー定義コンストラクタを使用する様々な側面を説明します。

この項の内容は次のとおりです。

属性値コンストラクタ

属性値コンストラクタとも呼ばれるシステム定義コンストラクタの場合、型の各属性値をコンストラクタに渡す必要があります。すると、例8-9に示すように、コンストラクタにより、新しいオブジェクト・インスタンスの属性にこれらの値が設定されます。

例8-9 コンストラクタによる属性値の設定

CREATE TYPE shape AS OBJECT (
    name VARCHAR2(30),
    area NUMBER);
/
CREATE TABLE building_blocks of shape;

-- attribute-value constructor: Sets instance attributes to the specified values
INSERT INTO building_blocks
  VALUES (
    NEW shape('my_shape', 4));

NEWは、コンストラクタへのコールの前にオプションで追加するキーワードです。このキーワードを追加することをお薦めします。

コンストラクタと型進化

属性値コンストラクタを使用することにより、型に対して独自のコンストラクタを定義する必要がなくなります。ただし、型に宣言されたすべての属性に対して値を指定する必要があり、指定しない場合はコンストラクタ・コールのコンパイルに失敗します。

ユーザー定義コンストラクタと異なり、特に属性値コンストラクタは暗黙的でコードに表示されないため、後で型を進化させる場合、この要件によって問題が発生することがあります。型の属性を変更した場合は、その型の属性値コンストラクタも変更されます。属性を追加した場合、更新された属性値コンストラクタは、新しい属性に対する値が指定されるものとみなします。それ以外の場合は、既存のコード内の属性値コンストラクタへのコールが失敗します。

「型進化」を参照してください。

ユーザー定義コンストラクタの利点

ユーザー定義コンストラクタは、属性値コンストラクタと異なり、型の各属性に対する値を明示的に設定する必要がありません。ユーザー定義コンストラクタは、任意の型の任意の数の引数を取ることができ、これらの引数は型の属性に直接マップする必要がありません。コンストラクタを定義する場合、属性を任意の適切な値に初期化できます。値が指定されない属性は、システムによってNULLに初期化されます。

たとえば、属性を追加して型を進化させる場合、その型に対するユーザー定義コンストラクタへのコールは変更する必要がありません。型を進化させる場合、ユーザー定義コンストラクタは自動的に変更されないため、シグネチャは同じままです。ただし、新しい属性をNULLに初期化しない場合は、コンストラクタの定義の変更が必要になることがあります。

ユーザー定義コンストラクタの定義および実装

ユーザー定義コンストラクタは、通常のメソッドと同様に型本体に定義します。ユーザー定義コンストラクタの宣言および定義は、CONSTRUCTOR FUNCTION句を使用し、RETURN SELF AS RESULT句で終了します。

型のコンストラクタには、型と同じ名前を使用する必要があります。例8-10では、shape型の2つのコンストラクタ・ファンクションを定義します。例に示すとおり、異なるシグネチャを持つ複数のバージョンを定義することにより、ユーザー定義コンストラクタをオーバーロードできます。

例8-10 ユーザー定義コンストラクタの定義および実装

CREATE TYPE shape AS OBJECT (
    name VARCHAR2(30),
    area NUMBER,
    CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2)
                               RETURN SELF AS RESULT,
    CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2, 
                               area NUMBER) RETURN SELF AS RESULT
) NOT FINAL;
/

CREATE TYPE BODY shape AS
    CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2) 
                               RETURN SELF AS RESULT IS
    BEGIN
        SELF.name := name;
        SELF.area := 0;
        RETURN;
    END;
    CONSTRUCTOR FUNCTION shape(SELF IN OUT NOCOPY shape, name VARCHAR2, 
                                area NUMBER) RETURN SELF AS RESULT IS
    BEGIN
        SELF.name := name;
        SELF.area := area;
        RETURN;
    END;
END;
/

ユーザー定義コンストラクタには、暗黙的な第1パラメータSELFがあります。ユーザー定義コンストラクタの宣言では、このパラメータの指定はオプションです。指定する場合、このパラメータのモードはIN OUTとして宣言する必要があります。

必須句RETURN SELF AS RESULTによって、戻されるインスタンスの最も狭い意味での型は、必ずSELF引数の最も狭い意味での型と同じになります。コンストラクタの場合、この型は、コンストラクタが定義された型です。shapeコンストラクタへのコールに対するSELF引数の最も狭い意味での型がshapeの場合、この句によってshapeコンストラクタからはshapeのサブタイプのインスタンスではなくshapeのインスタンスが必ず戻されます。

コンストラクタ・ファンクションがコールされると、システムはSELF引数の属性をNULLに初期化します。例8-10SELF.nameなど、ファンクション本体で初期化される後続の属性名は、コンストラクタ・ファンクションの引数の名前と区別するために、SELFで修飾できます(これらの名前が同一の場合)。引数の名前が異なる場合、この修飾は不要です。

例に示すとおり、ファンクション本体には、明示的なreturn;を含める必要があります。ただし、returnキーワードの後に、return式を続けることはできません。システムは、新しく作成されたSELFインスタンスを自動的に戻します。

ユーザー定義コンストラクタは、PL/SQL、CまたはJavaで実装できます。

コンストラクタのオーバーロードおよび隠蔽

他の型のメソッドと同様、ユーザー定義コンストラクタもオーバーロードできます。

ユーザー定義コンストラクタは継承されないため、スーパータイプで定義されたユーザー定義コンストラクタはサブタイプに隠蔽できません。ただし、ユーザー定義コンストラクタのシグネチャが属性値コンストラクタのシグネチャと完全に一致する場合、ユーザー定義コンストラクタはその型の属性値コンストラクタを隠蔽し、これを置き換えます。シグネチャが一致するには、ユーザー定義コンストラクタのパラメータ(暗黙的なSELFパラメータの後)の名前と型が、その型の属性の名前と型と同じである必要があります。ユーザー定義コンストラクタのパラメータ(暗黙的なSELFパラメータの後)のモードは、必ずINにしてください。

同じ名前とシグネチャを持つユーザー定義コンストラクタによって属性値コンストラクタが隠蔽されていない場合は、継続して属性値コンストラクタをコールできます。

たとえば、属性の追加により型が進化する場合は、型の属性値コンストラクタのシグネチャもそれに対応して変更することに注意してください。これによって、以前に隠蔽されていた属性値コンストラクタが再度使用可能になります。

ユーザー定義コンストラクタのコール

他のすべてのファンクションと同様にユーザー定義コンストラクタをコールし、通常のファンクションが使用できるすべての場所で使用できます。

SELF引数は、暗黙的に渡され、明示的に渡されません。つまり、次のように使用することはできません。

NEW constructor(instance, argument_list)

CREATEまたはALTER TABLE文のDEFAULT句には、ユーザー定義コンストラクタは指定できませんが、属性値コンストラクタは指定できます。属性値コンストラクタの引数には、PL/SQLファンクションまたは他の列(疑似列LEVELPRIORROWNUMなど)の参照、あるいは完全に指定されていない日付定数の参照を含めることはできません。CHECK制約式についても同様です。表の作成中または変更中に、属性値コンストラクタはCHECK制約式の一部として使用できますが、ユーザー定義コンストラクタは使用できません。

SQLでは、引数を持たないコンストラクタ・コールについても、カッコを付ける必要があります。PL/SQLでは、引数を持たないコンストラクタを起動する場合、カッコはオプションです。ただし、カッコを付けた方が、コンストラクタ・コールがファンクション・コールであることがより明確になります。次のPL/SQL例では、新しいshapeを作成するためのコンストラクタ・コールのカッコが省略されています。

shape s := NEW my_schema.shape;

NEWキーワードおよびスキーマ名はオプションで使用してください。

例8-11では、例8-10で作成した型の下にサブタイプを作成し、ユーザー定義コンストラクタをコールする例を示します。

例8-11 ユーザー定義コンストラクタのコール

-- Requires Ex. 8-10
CREATE TYPE rectangle UNDER shape (
    len NUMBER,
    wth NUMBER,
    CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
        name VARCHAR2, len NUMBER, wth NUMBER) RETURN SELF as RESULT,
    CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
        name VARCHAR2, side NUMBER) RETURN SELF as RESULT);
/
SHOW ERRORS
CREATE TYPE BODY rectangle IS 
    CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
        name VARCHAR2, len NUMBER, wth NUMBER) RETURN  SELF AS RESULT IS
    BEGIN 
        SELF.name := name;
        SELF.area := len*wth;
        SELF.len := len;
        SELF.wth := wth;
        RETURN ;
    END;
    CONSTRUCTOR FUNCTION rectangle(SELF IN OUT NOCOPY rectangle,
        name VARCHAR2, side NUMBER) RETURN  SELF AS RESULT IS
    BEGIN 
        SELF.name := name;
        SELF.area := side * side;
        SELF.len := side;
        SELF.wth := side;
        RETURN ;
    END;
END;
/

CREATE TABLE shape_table OF shape;
INSERT INTO shape_table VALUES(shape('shape1')); 
INSERT INTO shape_table VALUES(shape('shape2', 20)); 
INSERT INTO shape_table VALUES(rectangle('rectangle', 2, 5)); 
INSERT INTO shape_table VALUES(rectangle('quadrangle', 12, 3));
INSERT INTO shape_table VALUES(rectangle('square', 12));

次の問合せでは、shape_table内の行を選択します。

SELECT VALUE(s) FROM shape_table s;

VALUE(S)(NAME, AREA)
---------------------------------------------
SHAPE('shape1', 0)
SHAPE('shape2', 20)
RECTANGLE('rectangle', 10, 2, 5)
RECTANGLE('quadrangle', 36, 12, 3)
RECTANGLE('square', 144, 12, 12)

次のPL/SQLコードは、コンストラクタをコールします。

s shape := NEW shape('void');

SQLJオブジェクト型のコンストラクタ

SQLJオブジェクト型は、JavaクラスにマップされるSQLオブジェクト型です。SQLJオブジェクト型は属性値コンストラクタを持ちます。このオブジェクト型は、参照されたJavaクラスでコンストラクタにマップされるユーザー定義コンストラクタを持つこともできます。

例8-12 SQLJオブジェクトの作成

CREATE TYPE address AS OBJECT 
   EXTERNAL NAME 'university.address' LANGUAGE JAVA
   USING SQLData(
     street   VARCHAR2(100) EXTERNAL NAME 'street',
     city     VARCHAR2(50)  EXTERNAL NAME 'city',
     state    VARCHAR2(50)  EXTERNAL NAME 'state',
     zipcode  NUMBER        EXTERNAL NAME 'zipcode',
    CONSTRUCTOR FUNCTION address (SELF IN OUT NOCOPY address, street VARCHAR2,
                                  city VARCHAR2, state VARCHAR2, zipcode NUMBER)
      RETURN SELF AS RESULT AS LANGUAGE JAVA
      NAME  'university.address (java.lang.String, java.lang.String,
                      java.lang.String, int) return address');
/

シリアル化表現のSQLJ型は、ユーザー定義コンストラクタのみ持つことができます。SQLJ型のオブジェクトの内部表現は、SQLにとって不透明であるため、SQLJ型に属性値コンストラクタは使用できません。

一時型および汎用型

Oracle Databaseには、型の記述、データ・インスタンス、およびオブジェクト型やコレクション型を含むその他のSQL型のデータ・インスタンスの集合の動的なカプセル化およびアクセスを可能にする3つの特殊なSQLデータ型があります。この3つの型は、匿名のコレクション型を含めた匿名型の作成にも使用できます。

この3つのSQL型は、不透明型として実装されます。つまり、これらの型の内部構造は、データベースには認識されません。不透明型のデータへの問合せは、目的に合ったファンクション(通常は3GLルーチン)を実装することによってのみ実行されます。Oracle Databaseは、そのようなファンクションを実装するためにOCIとPL/SQL APIの両方を提供しています。

一時型の構造は、データベースにとって不透明です。そのため、それらは永続的に格納することはできません。一時型の列は作成できず、永続型の属性にできません。

表8-2で、この3つの汎用SQL型を説明します。

表8-2 汎用SQL型

説明

SYS.ANYTYPE

型記述型。SYS.ANYTYPEには、名前が付いているか付いていないかにかかわらず、オブジェクト型およびコレクション型を含めた、任意のSQL型の型記述を含めることができます。

ANYTYPEには、永続型の型の記述を含めることができますが、ANYTYPE自体は一時型です。つまり、ANYTYPE自体の値がデータベースに自動的に格納されることはありません。永続型を作成するには、SQLからCREATE TYPE文を使用します。

SYS.ANYDATA

自己記述的データ・インスタンスの型。SYS.ANYDATAには、与えられた型のインスタンス、データ、およびその型の記述が含まれています。SYS.ANYDATAは、この意味で自己記述的です。ANYDATAは、データベースに永続的に格納できます。

次のものはANYDATA列に格納できません。

  • ANYDATAまたはXMLTYPEなどの別の不透明な型

  • LOB型(BLOB/CLOB/NCLOB)

  • 4Kより大きい最大サイズのVARRAY

  • 前述の型のいずれかを含むADT

  • 一時型

SYS.ANYDATASET

自己記述的なデータ集合の型。SYS.ANYDATASETには、与えられた型の記述、およびその型のデータ・インスタンスの集合が含まれています。ANYDATASETは、データベースに永続的に格納できます。

次のものはANYDATASET列に格納できません。

  • ANYDATAまたはXMLTYPEなどの別の不透明な型

  • LOB型(BLOB/CLOB/NCLOB)

  • 4Kより大きい最大サイズのVARRAY

  • 前述の型のいずれかを含むADT

  • 一時型


この3つの型はそれぞれ、データベースに対してネイティブな組込み型や、名前の有無にかかわらずオブジェクト型およびコレクション型と併用できます。型は、型記述、単独インスタンスおよび他の型のインスタンス・セットを動的に操作するための汎用的な方法を提供します。APIを使用すると、あらゆる種類の型について一時的なANYTYPE記述を作成できます。同様に、任意のSQL型のデータ値を作成するかANYDATAに変換(キャスト)し、ANYDATAをSQL型に変換できます。さらに、値セットとANYDATASETの場合も同様です。

汎用型は、ストアド・プロシージャを使用した作業を簡単にします。汎用型を使用して、標準型の記述およびデータをカプセル化し、カプセル化された情報を汎用型のパラメータに渡せます。プロシージャ本体では、カプセル化されたデータおよび任意の型の型記述の処理方法を詳細に記述できます。

また、基礎となる様々な型のカプセル化されたデータを、型ANYDATAまたはANYDATASETの単一の表の列に格納することもできます。たとえば、ANYDATAをアドバンスト・キューイングと併用して、異質な型のデータのキューイングをモデル化できます。基礎となるデータ型のデータは、他の任意のデータ同様に、問合せを実行できます。

例8-13では、SYS.ANYDATAに組み込まれたメソッドを使用して、SYS.ANYDATA表列に格納されているデータの情報にアクセスするPL/SQLプロシージャを定義して実行します。

例8-13 SYS.ANYDATAの使用

CREATE OR REPLACE TYPE dogowner AS OBJECT ( 
    ownerno NUMBER, ownername VARCHAR2(10) );
/
CREATE OR REPLACE TYPE dog AS OBJECT ( 
    breed VARCHAR2(10), dogname VARCHAR2(10) );
/
CREATE TABLE mytab ( id NUMBER, data SYS.ANYDATA );
INSERT INTO mytab VALUES ( 1, SYS.ANYDATA.ConvertNumber (5) );
INSERT INTO mytab VALUES ( 2, SYS.ANYDATA.ConvertObject (
    dogowner ( 5555, 'John') ) );
commit;

CREATE OR REPLACE procedure P IS
  CURSOR cur IS SELECT id, data FROM mytab;

  v_id mytab.id%TYPE;
  v_data mytab.data%TYPE;
  v_type SYS.ANYTYPE;
  v_typecode PLS_INTEGER;
  v_typename VARCHAR2(60);
  v_dummy PLS_INTEGER;
  v_n NUMBER;
  v_dogowner dogowner;
  non_null_anytype_for_NUMBER exception;
  unknown_typename exception;

BEGIN
  OPEN cur;
    LOOP
      FETCH cur INTO v_id, v_data;
      EXIT WHEN cur%NOTFOUND;
      v_typecode := v_data.GetType ( v_type /* OUT */ );
      CASE v_typecode
        WHEN Dbms_Types.Typecode_NUMBER THEN
          IF v_type IS NOT NULL
            THEN RAISE non_null_anytype_for_NUMBER; END IF;
          v_dummy := v_data.GetNUMBER ( v_n /* OUT */ );
          Dbms_Output.Put_Line (
            To_Char(v_id) || ': NUMBER = ' || To_Char(v_n) );
        WHEN Dbms_Types.Typecode_Object THEN
          v_typename := v_data.GetTypeName();
          IF v_typename NOT IN ( 'HR.DOGOWNER' )
            THEN RAISE unknown_typename; END IF;
          v_dummy := v_data.GetObject ( v_dogowner /* OUT */ );
          Dbms_Output.Put_Line (
            To_Char(v_id) || ': user-defined type = ' || v_typename ||
            '(' || v_dogowner.ownerno || ', ' || v_dogowner.ownername || ' )' );
      END CASE;
    END LOOP;
    CLOSE cur;

EXCEPTION
  WHEN non_null_anytype_for_NUMBER THEN
      RAISE_Application_Error ( -20000,
        'Paradox: the return AnyType instance FROM GetType ' ||
        'should be NULL for all but user-defined types' );
  WHEN unknown_typename THEN
      RAISE_Application_Error ( -20000,
        'Unknown user-defined type ' || v_typename ||
        ' - program written to handle only HR.DOGOWNER' );
END;
/

SELECT t.data.gettypename() FROM mytab t;
SET SERVEROUTPUT ON;
EXEC P;

前述にコード例の問合せおよびプロシージャPにより、次のような出力が生成されます。


T.DATA.GETTYPENAME()
-------------------------------------------------------------
SYS.NUMBER
HR.DOGOWNER

1: NUMBER = 5
2: user-defined type = HR.DOGOWNER(5555, John )

前述の3つの汎用SQL型に対応するのが、それらをモデル化するOCI型です。各OCI型は、それぞれの型の作成およびアクセスに使用する関数のセットを備えています。

  • OCIType: SYS.ANYTYPEに対応しています。

  • OCIAnyData: SYS.ANYDATAに対応しています。

  • OCIAnyDataSet: SYS.ANYDATASETに対応しています。


    関連項目:

    • OCITypeOCIAnyDataOCIAnyDataSet APIおよびそれらの使用方法の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

    • ANYTYPEANYDATAおよびANYDATASET型へのインタフェースの詳細と、ANYTYPEANYDATAおよびANYDATASETとともに使用するDBMS_TYPESパッケージ(組込み型およびユーザー定義型の定数を定義)の詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。


ユーザー定義集計ファンクション

Oracle Databaseは、レコード集合に対する操作に使用する、MAXMINおよびSUMをはじめとする数多くの定義済集計ファンクションを提供しています。これらの定義済集計ファンクションは、スカラー・データに対してのみ使用できます。ただし、これらのファンクションのカスタム実装を独自に作成することもできれば、複雑なデータ(たとえば、オブジェクト型、不透明型、LOB型を使用して格納されているマルチメディア・データなど)に対して使用する新しい集計ファンクションを定義することもできます。

ユーザー定義集計ファンクションは、Oracleデータベースの組込み集計ファンクションと同様に、SQL DML文で使用されます。このようなファンクションがサーバーに登録されていると、ネイティブのルーチンではなく、ユーザーが定義した集計ルーチンがコールされます。

ユーザー定義集計ファンクションは、スカラー・データに対しても使用できます。たとえば、財務アプリケーションまたは科学アプリケーションに対応付けられた複雑な統計データを処理するために特殊な集計ファンクションを実装すると効果的な場合があります。

ユーザー定義集計ファンクションは、拡張フレームワークの機能です。それらの実装には、ODCIAggregateインタフェース・ルーチンを使用します。


関連項目:

ODCIAggregateインタフェース・ルーチンを使用して、ユーザー定義集計ファンクションを実装する方法については、『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください。

ロケータでネストした表のパフォーマンスを向上させる方法

ネストした表のロケータを使用して、データの取得時にパフォーマンスを向上できます。

コレクション型は、C++やJavaなどの言語でのシステム固有の型または構造へ直接マップすることはありません。これらの言語を使用しているアプリケーションは、OCIなどのOracleデータベース・インタフェースを介して、コレクションの内容にアクセスする必要があります。

一般に、クライアントが(オブジェクトをフェッチすることによって)ネストした表に明示的または暗黙的にアクセスすると、コレクション値全体がクライアント・プロセスに戻されます。パフォーマンス上の理由から、クライアントは、コレクションの内容全体を取り出すのを遅延または回避する場合があります。Oracleデータベースでは、ネストした表の実際の値ではなくロケータを使用することによって、これに対処します。実際にコレクションの内容にアクセスが行われたときは、その内容がクライアントに自動的に転送されます。

ネストした表のロケータは、コレクション値へのハンドルに似ています。検索実行時のデータベース・スナップショットを確保することで、ネストした表の値またはコピー・セマンティクスを保とうとします。スナップショットによって、コレクション要素がロケータを使用してフェッチされたときに、データベースがネストした表の値の正しいインスタンスを取り出せるようになります。ロケータの有効範囲は1つのセッションにかぎられ、複数のセッションにまたがって使用することはできません。データベース・スナップショットが使用されているため、ネストした表の更新率が高い場合は、「スナップショットが古すぎます」というエラーが発生する場合があります。LOBロケータとは異なり、ネストした表のロケータは純粋なロケータであり、コレクション・インスタンスを変更するためには使用できません。


関連項目:

詳細は、「ネストした表のロケータ」を参照してください。