8.6 一時型と汎用型
Oracleデータベースには、型の記述、データ・インスタンス、およびオブジェクト型やコレクション型を含むその他のSQL型のデータ・インスタンスの集合の動的なカプセル化およびアクセスを可能にする3つの汎用(つまり、汎用的にプログラムされた)SQLデータ型があります。この3つの型は、匿名のコレクション型を含めた匿名型の作成にも使用できます。
この3つのSQL型は、不透明型として実装されます。つまり、これらの型の内部構造は、データベースには認識されません。そのデータへの問合せは、目的に合ったファンクション(通常は3GLルーチン)を実装することによってのみ実行されます。Oracleデータベースは、そのようなファンクションを実装するためにOCIとPL/SQL APIの両方を提供しています。
3つの型で、ANYTYPEは一時型であり、ANYDATAおよびANYDATASETは一時型ではなく永続型です。構造がデータベースにとって不透明であるため、一時型は永続的に格納できません。一時型の列は作成できず、永続型の属性にできません。
Oracle Database 12cリリース12.2以降、次の場合にActive Data Guardで一時型を作成できます。
-
リアルタイム適用がActive Data Guardで実行されている場合、および
-
ロジカル・スタンバイがプライマリに(通常、秒レベルで)後れを取っていない場合。
表8-2で、この3つの汎用SQL型を説明します。
表8-2 汎用SQL型
| 型 | 説明 |
|---|---|
|
|
型記述型。
|
|
|
自己記述的データ・インスタンスの型。 次のものは
|
|
|
自己記述的なデータ集合の型。 次のものは
|
この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型は、それぞれの型の作成およびアクセスに使用する関数のセットを備えています。
-
OCIType:SYS.ANYTYPEに対応しています。 -
OCIAnyData:SYS.ANYDATAに対応しています。 -
OCIAnyDataSet:SYS.ANYDATASETに対応しています。関連項目:
-
OCIType、OCIAnyData、OCIAnyDataSetAPIおよびそれらの使用方法の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照 -
ANYTYPE、ANYDATA、ANYDATASETの各型に対するインタフェース、およびANYTYPE、ANYDATA、ANYDATASETと併用するDBMS_TYPESパッケージ(組込み型およびユーザー定義型の定数を定義)の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照
-