ヘッダーをスキップ
Oracle Databaseオブジェクト・リレーショナル開発者ガイド
11gリリース1(11.1)
E05671-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

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

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

内容は次のとおりです。

オブジェクトの記憶域

オブジェクト型の複合構造を、単純な構造の表に自動的にマップします。

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

リーフ・レベル属性

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

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

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

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

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

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

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

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

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

代入可能な列および表の非表示列

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

たとえば、person_typの代入可能な列には、person_typの各属性、具体的にはidnonameおよびphoneに対する非表示列が対応付けられます。また、person_typのサブタイプの属性の非表示列も作成されます。たとえば、student_typに対するdept_idmajor、およびpart_time_student_typに対するnumber_hoursが作成されます。

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

サブタイプがDROP TYPEに対するVALIDATEオプションを使用して削除された場合は、各サブタイプの固有の属性に対するこのような非表示列はすべて、自動的に削除されます。

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

指定されたオブジェクト・インスタンスの型IDは、ファンクションSYS_TYPEIDを使用して特定できます。たとえば、代入可能なオブジェクト表person_obj_tableに、例2-20に示す3つの行があるとします。

例8-1の問合せによって、この表に格納されているオブジェクト・インスタンスの型IDが取得されます。

例8-1 表の型IDの取得

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は、オブジェクト識別子(OID)、オブジェクト表のいくつかのメタデータ、およびROWID(オプション)で構成されます。

REF型の列にあるREFのサイズは、その列に対応付けられた記憶域プロパティに依存します。たとえば、列がREF WITH ROWIDとして宣言されている場合、ROWIDREF列に格納されます。ROWIDのヒントは、制約付きREF列にあるオブジェクト参照では無視されます。

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

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


注意:

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

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

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

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

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

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

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

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

VARRAYの内部レイアウト

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

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

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

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

型判別式の列の索引付け

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

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

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

CREATE BITMAP INDEX typeid_idx ON contacts (SYS_TYPEID(contact));

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

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

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

CREATE INDEX major1_idx ON contacts
  (TREAT(contact AS student_typ).major);

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

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

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

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

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

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

型進化

オブジェクト型の変更を、型進化といいます。オブジェクト型は、次の方法で変更できます。

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

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

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

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

型に依存表がある場合は、型に加えられた各属性に対して、新しい属性の型に依存する表に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への変更、またはNOT FINALからFINALへの変更

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

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

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

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

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

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')
-- add the email attribute and drop the phone attribute
ALTER TYPE person_typ
  ADD ATTRIBUTE (email VARCHAR2(80)),
  DROP ATTRIBUTE phone CASCADE NOT INCLUDING TABLE DATA;

-- Disconnect and reconnect to accommodate the type change
-- 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属性が含まれている場合、特に大きな効果があります。通常、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オプションは、他の表または依存オブジェクトが変換されないようにします。

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

この項では、型に複雑な変更を加える手順を説明します。この種の変更では、ネストした表に含まれているオブジェクト型に、ネストした表属性を追加する必要があります。影響を受けるネストした表をアップグレードするときに、新規の記憶表の名前を指定します。

次の、person_typオブジェクト型に基づくスキーマについて考えてみます。

CREATE TYPE people_typ AS TABLE OF person_typ;/
CREATE TYPE department_typ AS OBJECT (
  manager    person_typ,
  employee   people_typ);/
CREATE TABLE department OF department_typ
  NESTED TABLE employee STORE AS employee_store_nt;
  1. この型を変更するため、ALTER TYPE文を発行します。

    ALTER TYPE文にオプションが指定されていない場合、デフォルトの動作では、ターゲットの型に依存するオブジェクトが存在しないかを調べます。なんらかの依存オブジェクトが存在する場合は、この文は異常終了します。オプションのキーワードによって、型の変更を依存型および依存表に連鎖的に波及させることができます。

    例8-3ALTER TYPE文では、時間を節約するために型および表のチェックをすべて迂回して、依存オブジェクトを無効としています。表のデータには、有効化されるまでアクセスできません。

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

    -- Create and add a new nested table attribute to person_typ
    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. 必要な場合は、CREATE OR REPLACE TYPE BODYを使用して、対応する型本体を更新して、新しい型定義に更新します。

  3. 依存表を最新の型バージョンにアップグレードし、表データを変換します。

    例8-4 依存表のアップグレード

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

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

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

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

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

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

依存表が存在する場合は、さらにチェックが行われて、表および索引に関連する制約が遵守されているかが確認されます。ここでも、ALTER TYPE文について、表に関連する制約のチェックが失敗すると、型の変更は異常終了し、その型の新しいバージョンは作成されません。

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

次に例を示します。

CREATE TYPE mytype AS OBJECT (attr1 NUMBER, attr2 NUMBER);
/
ALTER TYPE mytype ADD ATTRIBUTE (attr3 NUMBER),
  DROP ATTRIBUTE attr2,
  ADD ATTRIBUTE attr4 NUMBER CASCADE;

この結果、mytypeの定義は次のようになります。

(attr1 NUMBER, attr3 NUMBER, attr4 NUMBER);

次のALTER TYPE文は、同じ属性(attr5)に対して複数の変更を加えようとするもので、これは無効です。

-- invalid ALTER TYPE statement
ALTER TYPE mytype ADD ATTRIBUTE (attr5 NUMBER, attr6 CHAR(10)),
  DROP ATTRIBUTE attr5;

次に、妥当性チェックに対する制約、表の制限、および型に対して可能な様々な種類の変更についてのその他の情報に関する注意事項を示します。

属性の削除

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

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

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

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

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

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

長さ、精度またはスケールを増大するための属性の型の変更

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

メソッドの削除

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

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

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

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

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

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

FINALプロパティまたはINSTANTIABLEプロパティの修正

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

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

  • ターゲットの型にサブタイプがない場合にかぎり、オブジェクト型を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-5 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文の一部の重要なオプションを示します。

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

オプション 説明

INVALIDATE

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

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

CASCADE

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

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

INCLUDING TABLE DATA

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

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

NOT INCLUDING TABLE DATA

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

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

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

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

FORCE

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

CONVERT TO SUBSTITUTABLE

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

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



関連項目

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

図8-1に、ALTER TYPE INVALIDATEのオプションとその影響を示します。この図で、T1は型、T2は依存型です。後述の図に関する注意も参照してください。

図8-1 ALTER TYPEオプション

図8-1の説明
「図8-1 ALTER TYPEオプション」の説明

図に関する注意:

  1. Invalidate: (1)の線の下のすべてのオブジェクトは無効とマークされます。

  2. Cascade Not Including Table Data: (2)の線の下のすべてのオブジェクトは無効とマークされます。すべての依存表のメタデータを最新の型バージョンにアップグレードしますが、表データは変換されません。

  3. Cascade Including Table Data: (3)の線の下のすべてのオブジェクトは無効とマークされます。表データも含め、すべての依存表が最新の型バージョンにアップグレードされます。

型進化に使用するALTER TABLE文

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


関連項目

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

属性値コンストラクタ

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

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

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-7では、shape型の2つのコンストラクタ・ファンクションを定義します。例に示すとおり、異なるシグネチャを持つ複数のバージョンを定義することにより、ユーザー定義コンストラクタをオーバーロードできます。

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

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に初期化します。前述の例に示すとおり、ファンクション本体で初期化される後続の属性名は、コンストラクタ・ファンクションの引数の名前と区別するために、SELFで修飾できます(これらの名前が同一の場合)。引数の名前が異なる場合、このような修飾は不要です。次に例を示します。

SELF.name := name;

または

name := p1;

例に示すとおり、ファンクション本体には、明示的な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-8では、例8-7で作成した型の下にサブタイプを作成し、ユーザー定義コンストラクタをコールする例を示します。

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

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

この3つのSQL型は、不透明型として実装されます。つまり、これらの型の内部構造は、データベースには認識されません。不透明型のデータへの問合せは、目的に合ったファンクション(通常は3GLルーチン)を実装することによってのみ実行されます。Oracleは、そのようなファンクションを実装するために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は、データベースに永続的に格納できます。

SYS.ANYDATASET

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


これらの3つの型はいずれも、データベースに対してネイティブな任意の組込み型と併用できます。また、名前が付いているかどうかにかかわらず、オブジェクト型やコレクション型とも併用できます。これらの型は、型の記述、ローン・インスタンスおよび他の型のインスタンスの集合と動的に連携する汎用手段となります。APIを使用して、任意の型に対して一時的なANYTYPE記述を作成できます。同様に、任意のSQL型のデータ値を作成またはANYDATAに変換(キャスト)できます。また、ANYDATAを、SQL型に変換(して戻すことが)できます。また、値の集合とANYDATASETの場合も同様です。

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

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

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

例8-10 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型は、それぞれの型の作成およびアクセスに使用する関数のセットを備えています。

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

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

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

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

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


関連項目

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

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

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

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

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