272 UTL_REF

UTL_REFパッケージは、参照ベースの操作をサポートするためのPL/SQLプロシージャを提供します。SQLと異なり、UTL_REFプロシージャでは、オブジェクト表名が不明でも汎用タイプ・メソッドを書き込むことができます。

この章のトピックは、次のとおりです:

272.1 UTL_REFの概要

UTL_REFプロシージャでは、オブジェクト表名が不明でも汎用タイプ・メソッドを書き込むことができます。

Oracleは、ユーザー定義のコンポジット・タイプまたはオブジェクト・タイプをサポートします。オブジェクト・タイプのインスタンスをオブジェクトと呼びます。オブジェクト・タイプは、列のタイプとしてまたは表のタイプとして使用できます。

オブジェクト表では、表の各行にオブジェクトが格納されています。オブジェクト表にあるオブジェクトは、オブジェクト識別子で一意に識別できます。

参照はオブジェクトへの持続ポインタで、各参照にはオブジェクト識別子を含めることができます。参照は、オブジェクト・タイプの属性にしたり、表の列に格納することができます。参照を指定して、オブジェクトを取り出すことができます。

272.2 UTL_REFのセキュリティ・モデル

このパッケージを使用するには、プロシージャ・オプションが必要です。このパッケージは、SYS (CONNECT /AS SYSDBA)によって作成される必要があります。このパッケージが提供する操作は、パッケージ所有者SYSではなく、現行のコール・ユーザーのもとで実行されます。

UTL_REFパッケージは、サーバー上のストアドPL/SQLプロシージャまたはパッケージとクライアント側のPL/SQLコードからも同様に使用できます。

サーバー上のPL/SQLプロシージャまたはパッケージから起動した場合、UTL_REFは、REFが指すオブジェクトに対する適切なアクセス権限が実行者にあることを検証します。

注意:

これは、定義者の権限で操作する、サーバー上のPL/SQLパッケージまたはプロシージャとは対照的で、パッケージ所有者には、必要な操作を実行するための適切な権限が必要です。

したがって、UTL_REFがユーザーのSYS権限で定義された場合、ユーザーAが参照からオブジェクトを選択するためにUTL_REF.SELECTを起動すると、ユーザーA(実行者)は、権限をチェックする必要があります。

クライアント側のPL/SQLコードから起動した場合、UTL_REFは、PL/SQLが実行されているクライアント・セッションの権限を使用して動作します。

272.3 UTL_REFのタイプ

オブジェクト・タイプは、ユーザーが定義するか、またはライブラリ・タイプとして提供されたコンポジット・データ・タイプです。

次の構文を使用して、オブジェクト・タイプemployee_typeを作成できます。

CREATE TYPE employee_type AS OBJECT (
   name    VARCHAR2(20),
   id      NUMBER,

member function GET_ID
    (name VARCHAR2) 
   RETURN MEMBER);

オブジェクト・タイプemployee_typeはユーザー定義タイプで、nameidの2つの属性およびメンバー・ファンクションのGET_ID()が含まれています。

次のSQL構文を使用して、オブジェクト表を作成できます。

CREATE TABLE employee_table OF employee_type;

272.4 UTL_REFの例外

UTL_REFファンクションの実行中に、様々な理由で例外が戻る場合があります。

たとえば、次の使用例では例外が発生します。
  • 選択したオブジェクトが存在しません。これには、次のいずれかの理由が考えられます。

    1. オブジェクトは削除されたか、指定された参照先がありません(無効です)。

    2. オブジェクト表は、削除されたか存在しません。

  • シリアル化可能トランザクションで、オブジェクトを変更またはロックできません。オブジェクトは、シリアル化可能トランザクションの開始後に、別のトランザクションで変更されました。

  • オブジェクトを選択または変更する権限がありません。UTL_REFサブプログラムのコール元は、選択または変更するオブジェクトに対する適切な権限が必要です。

表272-1 UTL_REFの例外

例外 説明

errnum == 942

権限が不十分です。

errnum == 1031

権限が不十分です。

errnum == 8177

シリアル化可能トランザクションの場合は、シリアル化できません。

errnum == 60

デッドロックが検出されました。

errnum == 1403

データが見つかりません(REFNULLである場合など)。

UTL_REFパッケージは、名前の付いた例外を定義しません。特定の例外を捕捉して適切に処理するために、ブロックを処理する例外を定義できます。

272.5 UTL_REFサブプログラムの要約

この表は、UTL_REFサブプログラムを示し、簡単に説明しています。

表272-2 UTL_REFパッケージのサブプログラム

サブプログラム 説明

DELETE_OBJECTプロシージャ

参照を指定してオブジェクトを削除します。

LOCK_OBJECTプロシージャ

参照を指定してオブジェクトをロックします。

SELECT_OBJECTプロシージャ

参照を指定してオブジェクトを選択します。

UPDATE_OBJECTプロシージャ

参照を指定してオブジェクトを更新します。

272.5.1 DELETE_OBJECTプロシージャ

このプロシージャは、参照を指定してオブジェクトを削除します。

このサブプログラムの意味は、次のSQL文に似ています。

DELETE FROM object_table  
WHERE REF(t) = reference; 

前述のSQL文と異なり、このサブプログラムでは、オブジェクトが常駐しているオブジェクト表名を指定する必要はありません。

構文

UTL_REF.DELETE_OBJECT (
   reference IN REF "<typename>"); 

パラメータ

表272-3 DELETE_OBJECTプロシージャのパラメータ

パラメータ 説明

reference

削除するオブジェクトの参照。

例外

発生する可能性があります。

この例は、次のシナリオを実行するためのUTL_REFパッケージの使用方法を示しています。会社の従業員が自宅住所の変更を上司に連絡するとします。

... Address_tの宣言など...

CREATE OR REPLACE TYPE Person_t ( 
   name    VARCHAR2(64), 
   gender  CHAR(1), 
   address Address_t, 
   MEMBER PROCEDURE setAddress(addr IN Address_t) 
); 

CREATE OR REPLACE TYPE BODY Person_t ( 
   MEMBER PROCEDURE setAddress(addr IN Address_t) IS 
   BEGIN 
      address := addr; 
   END; 
); 

CREATE OR REPLACE TYPE Employee_t (  

Person_tで、REFを使用したPerson_tへの継承の実装とsetAddressの委任をシミュレーションします。

   thePerson  REF Person_t, 
   empno      NUMBER(5), 
   deptREF    Department_t, 
   mgrREF     Employee_t, 
   reminders  StringArray_t, 
   MEMBER PROCEDURE setAddress(addr IN Address_t), 
   MEMBER procedure addReminder(reminder VARCHAR2); 
); 

CREATE TYPE BODY Employee_t ( 
   MEMBER PROCEDURE setAddress(addr IN Address_t) IS 
      myMgr Employee_t; 
      meAsPerson Person_t; 
   BEGIN 

責任をthePersonに委任して、アドレスを更新します。個人オブジェクトを参照からロックして、それをまた選択します。

      UTL_REF.LOCK_OBJECT(thePerson, meAsPerson); 
      meAsPerson.setAddress(addr);    

thePersonに委任します。

        UTL_REF.UPDATE_OBJECT(thePerson, meAsPerson); 
        if mgr is NOT NULL THEN 

マネージャに覚書きを渡します。

         UTL_REF.LOCK_OBJECT(mgr); 
         UTL_REF.SELECT_OBJECT(mgr, myMgr); 
         myMgr.addReminder 
         ('Update address in the employee directory for' || 
         thePerson.name || ', new address: ' || addr.asString); 
         UTL_REF.UPDATE_OBJECT(mgr, myMgr); 
      END IF; 
   EXCEPTION 
      WHEN OTHERS THEN 
      errnum := SQLCODE; 
      errmsg := SUBSTR(SQLERRM, 1, 200);

272.5.2 LOCK_OBJECTプロシージャ

このプロシージャは、参照を指定してオブジェクトをロックします。さらに、このプロシージャでは、プログラムによって、ロックされたオブジェクトを選択できます。

このサブプログラムの意味は、次のSQL文に似ています。

SELECT VALUE(t) 
  INTO object 
  FROM object_table t 
  WHERE REF(t) = reference 
  FOR UPDATE; 

前述のSQL文と異なり、このサブプログラムでは、オブジェクトが常駐しているオブジェクト表名を指定する必要はありません。オブジェクトの更新または削除前に、オブジェクトをロックする必要はありません。

構文

UTL_REF.LOCK_OBJECT (
   reference IN REF "<typename>"); 

UTL_REF.LOCK_OBJECT (
   reference IN REF "<typename>", 
   object    IN OUT "<typename>"); 

パラメータ

表272-4 LOCK_OBJECTプロシージャのパラメータ

パラメータ 説明

reference

ロックするオブジェクトの参照。

object

ロックされたオブジェクトを格納するPL/SQL変数。この変数は、ロックされたオブジェクトと同じオブジェクト・タイプである必要があります。

例外

発生する可能性があります。

272.5.3 SELECT_OBJECTプロシージャ

このプロシージャは、参照を指定してオブジェクトを選択します。選択されたオブジェクトはデータベースから取り出され、その値はPL/SQLの変数'object'に入れられます。

このサブプログラムの意味は、次のSQL文に似ています。

SELECT VALUE(t) 
INTO object 
FROM object_table t 
WHERE REF(t) = reference; 

前述のSQL文と異なり、このサブプログラムでは、オブジェクトが常駐しているオブジェクト表名を指定する必要はありません。

構文

UTL_REF.SELECT_OBJECT (
   reference IN REF "<typename>", 
   object    IN OUT "<typename>"); 

パラメータ

表272-5 SELECT_OBJECTプロシージャのパラメータ

パラメータ 説明

reference

選択または取り出すオブジェクトへの参照。

object

選択したオブジェクトを格納するPL/SQL変数。この変数は、参照されたオブジェクトと同じオブジェクト・タイプである必要があります。

例外

発生する可能性があります。

272.5.4 UPDATE_OBJECTプロシージャ

このプロシージャは、参照を指定してオブジェクトを更新します。参照されたオブジェクトは、PL/SQL変数'object'に含まれている値で更新されます。

このサブプログラムの意味は、次のSQL文に似ています。

UPDATE object_table t 
SET VALUE(t) = object 
WHERE REF(t) = reference; 

前述のSQL文と異なり、このサブプログラムでは、オブジェクトが常駐しているオブジェクト表名を指定する必要はありません。

構文

UTL_REF.UPDATE_OBJECT (
   reference IN REF "<typename>", 
   object    IN     "<typename>"); 

パラメータ

表272-6 UPDATE_OBJECTプロシージャのパラメータ

パラメータ 説明

reference

更新するオブジェクトの参照。

object

オブジェクトの新規の値を含めるPL/SQL変数。この変数は、更新されたオブジェクトと同じオブジェクト・タイプである必要があります。

例外

発生する可能性があります。