この章では、PL/SQLを使用してデータ・カートリッジのメソッドを実装する方法について説明します。メソッドとは、データ・カートリッジを使用して定義されたデータについて、許可される操作を定義するプロシージャおよびファンクションです。
この章の内容は、次のとおりです。
メソッドとは、オブジェクト型定義の一部で、その型の属性を操作できるプロシージャまたはファンクションのことです。この種のメソッドはメンバー・メソッドとも呼ばれ、オブジェクト型の構成要素として指定するときにキーワードMEMBERを取ります。
以降の各項では、メソッドの実装、メソッドのコールおよびメソッドでの属性の参照について、単純な例を使用して説明します。
|
関連項目
|
メソッドを実装するには、PL/SQLコードを作成し、それをCREATE TYPE BODY文で指定します。オブジェクト型にメソッドがない場合、そのオブジェクト型に対するCREATE TYPE BODY文は不要です。
例4-1に、rational_typeオブジェクト型の定義を示します。
例4-1 オブジェクト型の定義方法
CREATE TYPE rational_type AS OBJECT
( numerator INTEGER,
denominator INTEGER,
MAP MEMBER FUNCTION rat_to_real RETURN REAL,
MEMBER PROCEDURE normalize,
MEMBER FUNCTION plus (x rational_type)
RETURN rational_type);
例4-2の定義は、後述のCREATE TYPE BODY文でnormalizeメソッドの定義に使用するファンクションgcdを定義しています。
例4-2 「Greatest Common Divisor(最大公約数)」ファンクションの定義方法
CREATE FUNCTION gcd (x INTEGER, y INTEGER) RETURN INTEGER AS
-- Find greatest common divisor of x and y. For example, if
-- (8,12) is input, the greatest common divisor is 4.
-- This will be used in normalizing (simplifying) fractions.
-- (You need not try to understand how this code works, unless
-- you are a math wizard. It does.)
--
ans INTEGER;
BEGIN
IF (y <= x) AND (x MOD y = 0) THEN
ans := y;
ELSIF x < y THEN
ans := gcd(y, x); -- Recursive call
ELSE
ans := gcd(y, x MOD y); -- Recursive call
END IF;
RETURN ans;
END;
例4-3の文では、オブジェクト型rational_typeのメソッド(rat_to_real、normalizeおよびplus)を実装します。
例4-3 オブジェクト型に対するメソッドの実装方法
CREATE TYPE BODY rational_type
( MAP MEMBER FUNCTION rat_to_real RETURN REAL IS
-- The rat-to-real function converts a rational number to
-- a real number. For example, 6/8 = 0.75
BEGIN
RETURN numerator/denominator;
END;
-- The normalize procedure simplifies a fraction.
-- For example, 6/8 = 3/4
MEMBER PROCEDURE normalize IS
divisor INTEGER := gcd(numerator, denominator);
BEGIN
numerator := numerator/divisor;
denominator := denominator/divisor;
END;
-- The plus function adds a specified value to the
-- current value and returns a normalized result.
-- For example, 1/2 + 3/4 = 5/4
--
MEMBER FUNCTION plus(x rational_type)
RETURN rational_type IS
-- Return sum of SELF + x
BEGIN
r = rational_type(numerator*x.demonimator +
x.numerator*denominator,
denominator*x.denominator);
-- Example adding 1/2 to 3/4:
-- (3*2 + 1*4) / (4*2)
-- Now normalize (simplify). Here, 10/8 = 5/4
r.normalize;
RETURN r;
END;
END;
メソッドをコールするには、例4-4の構文を使用します。
SQL文でのみ例4-5の構文を使用できます。
例4-6に、PL/SQLでのメソッドget_emp_salのコール方法を示します。
例4-6 メソッドのコール方法(一般構文)
DECLARE employee employee_type; salary number; ... BEGIN salary := employee.get_emp_sal(); ... END;
メソッドをコールするには、SELF組込みパラメータを使用する方法もあります。各メソッドの暗黙的な第1パラメータはメソッドのコール対象となるオブジェクトの名前であるため、例4-7では、例4-6のsalary := employee.get_emp_sal();の行と同じアクションが実行されます。
この例では、employeeはget_emp_salメソッドのコール対象となるオブジェクトの名前です。
メンバー・メソッドは修飾子を使用せずに同じオブジェクト型の属性およびメンバー・メソッドを参照できるため、メソッドのコール対象となるオブジェクトには、常に組込み参照SELFが提供されます。
2つの文で変数var1の値が42に設定されている例4-8を考えてみます。
例4-8 変数値の設定方法
CREATE TYPE a_type AS OBJECT (
var1 INTEGER,
MEMBER PROCEDURE set_var1);
CREATE TYPE BODY a_type (
MEMBER PROCEDURE set_var1 IS
BEGIN
var1 := 42;
SELF.var1 := 42;
END set_var1;
);
文var1 := 42およびSELF.var1 := 42には同じ効果があります。var1はオブジェクト型a_typeの属性の名前で、set_var1はこのオブジェクト型のメンバー・メソッドであるため、メソッド・コードでは修飾なしでvar1にアクセスできます。ただし、コードの読みやすさとメンテナンス性を考慮して、このコンテキストにキーワードSELFを使用するとvar1を明確に参照できます。
パッケージとは、PL/SQLの型、オブジェクト、ストアド・プロシージャおよびファンクションのグループです。パッケージの仕様部では、パッケージの直接の有効範囲外で参照可能なパブリックな型、変数、定数およびサブプログラムが宣言されます。パッケージ本体では、仕様部で宣言されたオブジェクトと、パッケージ外部のアプリケーションから参照できないプライベート・オブジェクトが定義されます。
例4-9に、パッケージDS_packageのパッケージ仕様部を示します。このパッケージには2つのストアド・ファンクションds_findmaxおよびds_findmaxが含まれており、DataStreamオブジェクト型に対して定義されたDataStreamMinおよびDataStreamMaxファンクションを実装します。
例4-9 パッケージ仕様部の作成方法
create or replace package DS_package as
function ds_findmin(data clob) return pls_integer;
function ds_findmax(data clob) return pls_integer;
pragma restrict_references(ds_findmin, WNDS, WNPS);
pragma restrict_references(ds_findmax, WNDS, WNPS);
end;
|
関連項目
|
メンバー・ファンクションをコールするSQL文を実行するには、Oracleでファンクションの純正レベル、つまりファンクションによる副次効果が生じない範囲が認識される必要があります。副次効果という用語は、読取りまたは書込みのためのデータベース表、パッケージ変数などへのアクセスを指します。副次効果の制御が重要となるのは、問合せの正常なパラレル化を妨げたり、順序依存の(したがって不定な)結果が生成されたり、ユーザー・セッション間でパッケージの状態を維持するなどの許容されないアクションが必要になる可能性があるためです。
SQL文からコールされるメンバー・ファンクションを制限することで次の操作を禁止できます。
データベース表に対する挿入、更新または削除
パッケージ変数の値を読み取るか書き込む場合のリモート実行またはパラレル実行
パッケージ変数の値の書込み(SELECT、VALUESまたはSET句からコールされる場合を除く)
前述のいずれかのルールに違反する他のメソッドまたはサブプログラムのコール
前述のいずれかのルールに違反するビューの参照
プラグマRESTRICT_REFERENCES(コンパイラ・ディレクティブ)を使用して、これらのルールを規定する必要があります。例4-10では、DataStream型のDataStreamMaxメソッドの純正レベルは、write no database state(WNDS)およびwrite no package state(WNPS)としてアサートされます。
例4-10 型の純正レベルのアサート方法
CREATE TYPE DataStream AS OBJECT (
....
PRAGMA RESTRICT_REFERENCES (DataStreamMax, WNDS, WNPS)
... );
外部プロシージャの引数にはオブジェクト型を使用できないため、メンバー・メソッドで外部プロシージャをコールする場合は、直接はコールできません。パッケージを介してコールを送る必要があります。メンバー・ファンクションは、自動的に第1引数としてSELF参照を取得します。したがって、オブジェクト型のメンバー・メソッドで外部プロシージャを直接コールアウトすることはできません。
すべての外部コールをパッケージにまとめる方が設計としては適切です。パッケージの純正レベルもアサートする必要があります。したがって、DS_Packageというパッケージが宣言され、DataStream型からのすべての外部プロシージャ・コールがこのパッケージを介して送られる場合、例4-11のようにパッケージの純正レベルも宣言されます。
例4-11パッケージの純正レベルのアサート方法
CREATE OR REPLACE PACKAGE DS_Package AS ... PRAGMA RESTRICT_REFERENCES (ds_findmin, WNDS, WNPS) ... end;
WNDSおよびWNPSの他に、read no database state(RNDS)およびread no package state(RNPS)という2つの制約も指定できます。通常、この2つの制約が役立つのはパラレル問合せがある場合です。
各制約は相互に依存せず、暗黙的に指定しません。アプリケーション固有の要件に基づいて制約セットを選択してください。
メソッド名またはプロシージャ名のかわりにDEFAULTキーワードを指定することもできます。その場合、例4-12に示されているように、プラグマは型(またはパッケージのプロシージャ)のすべてのメンバー・ファンクションに適用されます。
例4-12 すべての型のメソッドおよびパッケージ・プロシージャに対するデフォルトの純正レベルのアサート方法
PRAGMA RESTRICT_REFERENCES (DEFAULT, WNDS, WNPS)
|
関連項目
|
スタンドアロン・プロシージャ、スタンドアロン・ファンクション、パッケージ仕様部または本体を作成するには、スキーマ内でプロシージャまたはパッケージを作成するためのCREATE PROCEDUREシステム権限、または他のユーザーのスキーマ内でプロシージャまたはパッケージを作成するためのCREATE ANY PROCEDUREシステム権限が必要です。
プロシージャまたはパッケージをコンパイルするには、そのプロシージャまたはパッケージの所有者は、コード本体で参照されるすべてのオブジェクトに対して必要なオブジェクト権限を明示的に付与されている必要があります。所有者がロールを介して必要な権限を取得することはできません。
プロシージャおよびファンクションを作成するための権限要件の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』のプロシージャおよびパッケージの使用に関する章を参照してください。
PL/SQLコードをデバッグする場合に最も単純な方法の1つは、SQL*Plusでメソッド、ブロックまたは文を対話形式で個別にテストし、問題があれば修正してから次の文に進むことです。エラー・メッセージの詳細が必要な場合は、SHOW ERRORS文を入力します。ランタイム・デバッグ用に文を表示することも考慮してください。例4-13に示されているように、コードにPUTおよびPUTLINE文を挿入し、変数と式の値を端末に出力することにより、ストアド・プロシージャおよびパッケージのデバッグには、DBMS_OUTPUTパッケージを使用できます。
PL/SQLトレース・ツールは、アプリケーション・コードの例外条件に関する詳細情報を提供します。このツールを使用すると、サーバー側PL/SQL文の実行をトレースできます。オブジェクト型のメソッドを直接トレースすることはできませんが、メソッドでコールするPL/SQLファンクションまたはプロシージャをトレースできます。また、このトレース・ツールでは、アプリケーション・コードの例外条件に関する情報も提供されます。トレース出力は、Oracleサーバーのトレース・ファイルに書き込まれます。ファイルにアクセスできるのは、データベース管理者のみです。
|
関連項目
|
CまたはC++プログラマにとっては、複数のPL/SQL表記規則と要件に違いがあります。
=は代入ではなく等号を意味します。
:=はAlgolではなく代入を意味します。
VARRAYは索引0ではなく索引1から始まります。
コメントは//または/*ではなく二重ハイフン(--)で始まります。
IF文にはTHENキーワードが必要です。
IF文にはEND IFキーワードが必要です(ELSE句がある場合はその後に挿入します)。
PRINTF文はありません。この文に相当する機能はDBMS_OUTPUT.PUT_LINE文です。この文では、リテラルと変数のテキストを二重縦線(||)で区切ります。
ファンクションには戻り値が必要で、プロシージャには戻り値を使用できません。
ファンクションをコールする場合は、代入演算子の右辺に置く必要があります。
PL/SQLキーワードの多くは、変数名として使用できません。
この項では、データ・カートリッジの作成に伴う数種類の誤りについて説明します。
13/19 PLS-00538: subprogram or cursor '<name>' is declared in an object
type specification and must be defined in the object type body
15/19 PLS-00539: subprogram '<name>' is declared in an object type body
and must be defined in the object type specification
前述のメッセージの一方または両方が表示される場合は、プロシージャまたはファンクションのシグネチャに誤りがあります。つまり、オブジェクト仕様部に入力したファンクションまたはプロシージャのプロトタイプと、オブジェクト本体内の定義に不一致があります。
パラメータの順序、スペル(大/小文字の区別を含む)およびファンクションの戻り値が同一であることを確認してください。入力エラーを防ぐには、コピーおよびペーストを使用します。
ORA-28576: lost RPC connection to external procedure agent ORA-06512: at "<name>", line <number> ORA-06512: at "<name>", line <number> ORA-06512: at line 34
このエラーは、DLLのデバッガを終了した後に発生する場合があります。デバッガの外でプログラムを再起動してください。
ERROR at line 1: ORA-04068: existing state of packages has been discarded ORA-04063: package body "<name>" has errors ORA-06508: PL/SQL: could not find program unit being called ORA-06512: at "<name>", line <number> ORA-06512: at line <number>
このエラーは、既存のデータ・カートリッジを拡張する際に発生することがあります。これは、パッケージが破損しており、再コンパイルする必要があることを示します。
再コンパイルを実行する前に、対象となるパッケージに依存する表およびオブジェクト型をすべて削除する必要があります。Windows NTシステム上で依存性を検索するには、Oracle Administratorツールバーを使用します。「スキーマ」ボタンをクリックし、sys\change_on_installとしてログインし、作成したパッケージと表を検索します。SQL*Plusインタフェースに次の書式のSQL文を入力して、これらのパッケージおよび表を削除します。
Drop type <type_name>; Drop table <table_name> cascade constraints;
これで、次の書式のSQL文を使用して再コンパイルを実行できます。
Alter type <type_name> compile body; or Alter type <type_name> compile specification;