メソッド
構造化タイプのデータベース・メソッドは、一連の入力データ値と、一連の結果値との関連のことです。 ここで、最初の入力値 (またはサブジェクト引数) は、メソッドと同じ値になるか、 サブジェクト・タイプ (サブジェクト・パラメーター ともいう) のサブタイプになります。
例えば、型が ADDRESS である CITY というメソッドは、 型が VARCHAR の入力データ値に渡すことができます。 結果は ADDRESS (または ADDRESS のサブタイプ) になります。
メソッドは、ユーザー定義構造化タイプの定義の一環として、暗黙的にあるいは明示的に定義されます。
暗黙的に定義されたメソッドは、構造化タイプごとに作成されます。 また、構造化タイプの属性ごとに、監視用メソッド が定義されます。 監視用メソッドを使うと、アプリケーション側は、 該当タイプのインスタンスの属性値を知ることができます。 変更メソッドも属性ごとに定義されます。 これにより、アプリケーション側では、 型インスタンスの属性の値を変更することによって型インスタンスを変更できます。 上記の CITY メソッドは、タイプ ADDRESS の mutator メソッドの一例です。
明示的に定義したメソッド、すなわちユーザー定義メソッド は、 CREATE TYPE (または ALTER TYPE ADD METHOD) および CREATE METHOD ステートメントを組み合わせて使用して、 SYSCAT.ROUTINES のデータベースに登録されるメソッドです。 特定の構造化タイプ用に定義されたメソッドはすべて、その型と同じスキーマで定義されます。
構造化タイプ用のユーザー定義メソッドは、 データベース・エンジンの構造化タイプ・インスタンスに適用できる (ユーザーもしくは第三者ベンダーによって提供された) メソッド定義を追加することによって、 データベース・システムの機能を拡張します。 データベース・メソッドを定義することにより、 データベースはアプリケーションが使用するのと同じメソッドをエンジンで活用することができ、 アプリケーションとデータベースとの間の相互作用が高まります。
外部および SQL ユーザー定義メソッド
ユーザー定義メソッドは、外部メソッドとするか、 SQL 式に基づくものとすることができます。 外部メソッドは、オブジェクト・コード・ライブラリーと、 メソッド呼び出し時に実行されるそのライブラリー内の関数によって、 データベースに対して定義されます。 SQL 式に基づいたメソッドは、メソッドの呼び出し時に、その SQL 式の結果を戻します。 そのようなメソッドでは、すべてが SQL で作成されているので、 オブジェクト・コード・ライブラリーが必要ありません。
ユーザー定義メソッドでは、呼び出されるたびに単一値の応答を戻すことができます。 この値は、構造化タイプとすることができます。 また、メソッドを (SELF AS RESULT を使用して) 型保持 として定義し、 メソッドの戻される型として、動的型のサブジェクト引数を戻すようにすることが可能です。 暗黙的に定義した変更メソッドは、型保持されます。
メソッド・シグニチャー
メソッドは、そのサブジェクト・タイプ、メソッド名、パラメーター数、 およびそのパラメーターのデータ・タイプによって識別されます。 これはメソッド・シグニチャー と呼ばれ、データベース内でユニークである必要があります。
- パラメーターの数やパラメーターのデータ・タイプが違う場合。または
- メソッドが同じメソッド階層の一部である場合 (つまり、 メソッド同士がオーバーライド関係にあるか、 同じ元のメソッドをオーバーライドしている場合)。または
- (最初のパラメーターとして、サブジェクト・タイプ、 またはそのサブタイプかスーパータイプを使用した) 同じ関数シグニチャーが存在しない場合。
複数のメソッド・インスタンスを持つメソッド名のことを、多重定義メソッド といいます。 あるメソッド名があるタイプ内で多重定義される場合、そのタイプには、 その名前で 2 つ以上のメソッドがあるということです (それぞれのタイプにはすべて、 異なるパラメーター・タイプがあります)。 メソッド名はサブジェクト・タイプ階層においても多重定義可能です。 その場合、そのタイプ階層にその名前のメソッドが 2 つ以上ありますが、 それぞれのメソッドには異なるパラメーター・タイプがなければなりません。
メソッドを呼び出すときには (許可されているコンテキストで) 構造化タイプ・インスタンス (サブジェクト引数) への参照と、二重ドット演算子の両方が先頭に記されているメソッド名を参照します。 その後に、括弧で囲まれた引数のリストが続きます。 実際に呼び出されるメソッドは、次の項で説明されているメソッド解決プロセスにより、 静的タイプのサブジェクト・タイプに基づいて決定されます。 関数呼び出しを使い、WITH FUNCTION ACCESS で定義されているメソッドを呼び出すこともできます。 その場合、関数解決のための通常の規則が適用されます。
関数解決の結果が WITH FUNCTION ACCESS で定義されているメソッドであれば、 メソッド呼び出しのその後のステップはすべて処理されます。
メソッドへのアクセスは EXECUTE 特権を通して制御されます。 GRANT および REVOKE ステートメントは、 特定のメソッドまたはメソッドのセットを誰が実行できて誰ができないのかを指定するために使用します。 メソッドを呼び出すには、EXECUTE 特権 (または DATAACCESS 権限) が必要です。 メソッドの定義者には、自動的に EXECUTE 特権が付与されます。 すべての基礎オブジェクトに対する WITH GRANT オプションを持つ外部メソッドまたは SQL メソッドの定義者にはまた、 メソッドに対する EXECUTE 特権付きの WITH GRANT オプションが GRANT されます。 定義者 (または ACCESSCTRL または SECADM 権限を持つ許可 ID) は、これを、任意の SQL ステートメントからメソッドを呼び出したり、任意の DDL ステートメント (CREATE VIEW、CREATE TRIGGER、または制約を定義するときなど) でメソッドを参照したりしたいユーザーに付与します。 ユーザーに EXECUTE 特権が付与されていない場合、 そのメソッドは、たとえ一致の度合いが高くても、メソッド解決アルゴリズムによって考慮されません。
メソッド解決
メソッドの呼び出しの後、データベース・マネージャーは、 同じ名前を持つ呼び出し可能なメソッドの中でどれが「最適」かを判別する必要があります。 メソッド解決時には、関数 (組み込みまたはユーザー定義) は考慮されません。
引数とは、呼び出し時にメソッドに渡される値です。 SQL の中で呼び出されるとき、メソッドには (特定構造化タイプの) サブジェクト引数、 およびゼロ個以上の引数のリストが渡されます。 このような引数は、引数のセマンティクスが引数リスト内の位置によって決定されるという意味で定位置と言えます。 パラメーター は、メソッドへの入力の形式上の定義です。 メソッドがデータベースに対して暗黙的に (特定タイプ用にシステム生成される)、 またはユーザーによって (ユーザー定義メソッド) 定義されるとき、 メソッドのパラメーターが (最初のパラメーターとしてのサブジェクト・パラメーター付きで) 指定されます。 パラメーターの定義の順序がパラメーターの位置、 およびその結果としてパラメーターのセマンティクスを定義することになります。 したがって、どのパラメーターもメソッドの特定の定位置入力です。 呼び出し時に、引数リスト中のその位置によって、引数は特定のパラメーターに対応します。
データベース・マネージャーは、呼び出しで指定されるメソッド名、メソッドに対する EXECUTE 特権、引数の数とデータ・タイプ、 サブジェクト引数の静的タイプ (およびそのスーパータイプ) 用に同じ名前を持つすべてのメソッド、 対応するパラメーターのデータ・タイプを使用して、あるメソッドを選択するかどうかの判断基準とします。 メソッドを決定する過程で発生する可能性のある結果について以下に示します。
- 特定のメソッドが最適であると判断される場合。
例えば、シグニチャーが以下のように定義されたタイプ SITE の RISK というメソッドを考えてみます。
続くメソッドの呼び出しは次のようになります (ここで、ST は SITE 列、DB は DOUBLE 列です)。PROXIMITY(INTEGER) FOR SITE PROXIMITY(DOUBLE) FOR SITE
この場合は、2 番目の PROXIMITY が選択されます。SELECT ST..PROXIMITY(DB) ...以下のようにメソッドが呼び出される場合は (SI は SMALLINT 列)、
最初の PROXIMITY が選択されます。 これは、SMALLINT は INTEGER にプロモート可能であり、 優先順位リストでの順位がさらに下になる DOUBLE よりも一致性が高いためです。SELECT ST..PROXIMITY(SI) ...構造化タイプである引数について考慮する場合、優先順位リストには、 静的タイプの引数のスーパータイプが入っています。 最適なのは、構造化タイプ階層の中で、 静的タイプの関数引数に最も近いスーパータイプ・パラメーターで定義する関数です。
- 許容できる適合性を持つメソッドがないと判断される場合。
例えば、前出の例と同じ 2 つの関数が指定され、
以下のように関数が参照されたとします (C は CHAR(5) 列)。
この場合、引数はどちらの PROXIMITY 関数のパラメーターとも整合性がありません。SELECT ST..PROXIMITY(C) ... - タイプ階層のメソッド、
および呼び出し時に渡される引数の数とデータ・タイプに基づいて特定のメソッドが選択される場合。
例えば、シグニチャーが以下のように定義された、
タイプ SITE および DRILLSITE (SITE のサブタイプ) の RISK というメソッドを考えてみます。
続くメソッドの呼び出しは次のようになります (ここで、DRST は DRILLSITE 列、DB は DOUBLE 列です)。RISK(INTEGER) FOR DRILLSITE RISK(DOUBLE) FOR SITE
DRILLSITE は SITE へプロモートできるので、この場合は、2 番目の RISK が選択されます。SELECT DRST..RISK(DB) ...以下のようにメソッドが参照される場合は (SI は SMALLINT 列)、
最初の RISK が選択されます。 これは、 SMALLINT は INTEGER にプロモート可能 (優先順位リストでの順位が DOUBLE よりも近い) であり、 DRILLSITE は、SITE よりも一致性が高いスーパータイプであるためです。SELECT DRST..RISK(SI) ...同じタイプ階層内のメソッドで同じシグニチャーを使い、 サブジェクト・パラメーター以外のパラメーターで利用することはできません。
最適の判別
引数のデータ・タイプと、 対象とするメソッドのパラメーターに定義されているデータ・タイプとの比較は、 似通った名前のメソッドのグループ中でどれが「最適」かを決定する基準となります。 考慮しているメソッドの結果のデータ・タイプは、この決定には関係しないことに注意してください。
メソッド解決の場合、最適を判別する際に、入力引数のデータ・タイプを、対応するパラメーターのデータ・タイプにプロモートできるかどうかが考慮されます。関数解決とは違って、最適を判別する際に、入力引数を対応するパラメーターのデータ・タイプに暗黙にキャストできるかどうかは考慮されません。モジュール中ではメソッドを定義できないので、メソッド解決時にはモジュールは考慮されません。
メソッド解決は、以下の手順で実行されます。
- まず、カタログ (SYSCAT.ROUTINES) から、
以下のすべての条件が真となるすべてのメソッドを探します。
- メソッド名が呼び出し名と同じで、サブジェクト・パラメーターが、 サブジェクト引数の静的タイプと同じであるか、そのスーパータイプである。
- 呼び出し側がメソッドに対する EXECUTE 特権を持っている。
- 定義済みパラメーターの数が呼び出しと一致している。
- 呼び出しの各引数のデータ・タイプが、 メソッドの対応する定義済みパラメーターのデータ・タイプに一致するか、 またはそのデータ・タイプに「プロモート可能」である。
- 次に、メソッド呼び出しの個々の引数を左から右に検討していきます。
左端の引数 (すなわち最初の引数) は、暗黙的な SELF パラメーターです。
例えば、タイプ ADDRESS_T に定義したメソッドには、暗黙的な最初のパラメーターとしてタイプ ADDRESS_T があります。引数ごとに、その引数に対して最適な一致ではない関数をすべて除去していきます。
ある引数の最適な一致とは、
その引数データ・タイプに対応する優先順位リストの中で、
そのデータ・タイプのパラメーターを持つ関数が存在するデータ・タイプのうち、
最初に記述されているデータ・タイプです。
長さ、精度、位取り、および FOR BIT DATA 属性は、この比較では考慮されません。
例えば、DECIMAL(9,1) の引数は DECIMAL(6,5) のパラメーターと完全に一致すると見なされ、
DECFLOAT(34) の引数は DECFLOAT(16) のパラメーターと完全に一致すると見なされ、また VARCHAR(19) の引数は VARCHAR(6) のパラメーターと完全に一致すると見なされます。
ユーザー定義構造化タイプ引数に最適なのは、それ自身です。 次に適しているのは、すぐ上のスーパータイプです。 このことは、引数の各スーパータイプに当てはまります。 ここで考慮しているのは、静的タイプ (宣言済みタイプ) の構造化タイプ引数であり、 動的タイプ (最も特定的なタイプ) ではありません。
- ほとんどの場合、ステップ 2 の実行後に候補メソッドが 1 つ残ります。 このメソッドを選択します。
- ステップ 2 の後で候補となるメソッドが残らなかった場合は、エラー (SQLSTATE 42884) になります。
メソッド解決の例
以下は、正常なメソッド解決の例を示しています。
CREATE METHOD FOO (CHAR(5), INT, DOUBLE) FOR HEADOFSTATE SPECIFIC FOO_1 ...
CREATE METHOD FOO (INT, INT, DOUBLE) FOR HEADOFSTATE SPECIFIC FOO_2 ...
CREATE METHOD FOO (INT, INT, DOUBLE, INT) FOR HEADOFSTATE SPECIFIC FOO_3 ...
CREATE METHOD FOO (INT, DOUBLE, DOUBLE) FOR EMPEROR SPECIFIC FOO_4 ...
CREATE METHOD FOO (INT, INT, DOUBLE) FOR EMPEROR SPECIFIC FOO_5 ...
CREATE METHOD FOO (SMALLINT, INT, DOUBLE) FOR EMPEROR SPECIFIC FOO_6 ...
CREATE METHOD FOO (INT, INT, DEC(7,2)) FOR GOVERNOR SPECIFIC FOO_7 ... SELECT E..FOO(I1, I2, D) ... アルゴリズムに従っていきます。
- タイプ GOVERNOR は EMPEROR のサブタイプなので (スーパータイプではない)、 FOO_7 は候補から除かれます。
- パラメーターの数が違っているため、FOO_3 は候補から除かれます。
- 第 1 引数 (サブジェクト引数ではない) が第 1 パラメーターのデータ・タイプにプロモートできないため、 FOO_1 と FOO_6 はどちらも候補から除かれます。 この時点で複数の候補が残っているため、次に引数が順に検討されます。
- サブジェクト引数の場合、FOO_2 はスーパータイプですが、 FOO_4 と FOO_5 はサブジェクト引数に一致しています。
- 最初の引数については、 残りのメソッド FOO_4 および FOO_5 がその引数タイプと完全に一致します。 この検討ではどのメソッドも検討の対象から除かれないため、 次の引数を検討する必要があります。
- 2 番目の引数では、FOO_5 が完全に一致しているのに対し、 FOO_4 は一致していないため、FOO_4 が検討の対象から除かれます。 これにより、メソッド FOO_5 が選ばれます。
メソッドの呼び出し
メソッドが選択された後も、いくつかの理由でそのメソッドの使用が許可されない場合があります。
STEP(SMALLINT) FOR TYPEA RETURNS CHAR(5)
STEP(DOUBLE) FOR TYPEA RETURNS INTEGER以下のようにメソッドが参照されると (S は SMALLINT 列で TA は TYPEA の列)、
SELECT 3 + TA..STEP(S) ... 引数タイプが完全に一致しているため、最初の STEP が選択されます。
しかし、結果のタイプが加算演算子の引数として求められる数値タイプではなく CHAR(5) であるため、
ステートメントではエラーになります。
選択されたメソッドから、 「メソッドの動的ディスパッチング」で記述されたアルゴリズムを使用して、 コンパイル時にディスパッチ可能なメソッドのセットが構築されます。 正確にどのメソッドが呼び出されるかは、 「メソッドの動的ディスパッチング」で記述されます。
- 関数解決に続く静的結果タイプは、 メソッド呼び出しのサブジェクト引数の静的タイプと同じです。
- メソッドを呼び出すときの動的結果タイプは、 メソッド呼び出しのサブジェクト引数の動的タイプと同じです。
メソッド呼び出しの引数が、選択されたメソッドのパラメーターのデータ・タイプと完全一致でない場合、 列への割り当てと同じ規則を適用して、 実行時に引数がパラメーターのデータ・タイプに変換されます。これには、引数とパラメーターの間で精度、位取り、 または長さが異なる場合も含まれます。ただし、引数の動的タイプが、 パラメーターの静的タイプのサブタイプである場合を除きます。
メソッドの動的ディスパッチング
メソッドは機能を提供し、あるタイプのデータをカプセル化します。 メソッドはあるタイプに対して定義され、常にこのタイプと関連付けることができます。 メソッドのパラメーターの 1 つは暗黙的な SELF パラメーターです。 SELF パラメーターは、 メソッドが宣言されているタイプのパラメーターです。 DML ステートメントでメソッドが呼び出されるときに SELF 引数として渡される引数は、 「サブジェクト」と呼ばれます。
メソッドがメソッド解決 (メソッド解決を参照) によって選択されているか、 あるいはメソッドが DDL ステートメントで指定されている場合、 そのメソッドは「最も具体的な適用可能許可メソッド」として認識されます。 サブジェクトが構造化タイプの場合、 そのメソッドは 1 つ以上のオーバーライド・メソッドを持つ可能性があります。 次に、実行時のサブジェクトの動的タイプ (最も具体的なタイプ) に基づいて、呼び出すメソッドを選択する決定が行われます。 この決定は「最も具体的なディスパッチ可能メソッドの決定」と呼ばれます。 このプロセスについて以下で説明します。
- 最も具体的な適用可能許可メソッドを備えたメソッド階層で元のメソッドを見つけます。 これは、ルート・メソッド と呼ばれます。
- ディスパッチ可能メソッドのセットを作成します。
これには以下が関与します。
- 最も具体的な適用可能許可メソッド。
- 最も具体的な適用可能許可メソッドをオーバーライドする任意のメソッド。 これは、この呼び出しのサブジェクトのサブタイプであるタイプに対して定義されます。
- 以下のように、最も具体的なディスパッチ可能メソッドを決定します。
- 一連のディスパッチ可能メソッドのエレメントで、 サブジェクトの動的タイプか、そのいずれかのスーパータイプのメソッドである任意のメソッドを開始します。 これは、初期の最も具体的なディスパッチ可能メソッドになります。
- 一連のディスパッチ可能メソッドのエレメントに関して上記を繰り返します。 各メソッドについて、 そのメソッドが、最も具体的なディスパッチ可能メソッドが定義されているタイプの適切なサブタイプのいずれかに対して定義されている場合、 および、そのメソッドが、サブジェクトの最も具体的なタイプのスーパータイプのいずれかに対して定義されている場合は、 そのメソッドを最も具体的なディスパッチ可能メソッドとして、ステップ 2 を繰り返します。
- 最も具体的なディスパッチ可能メソッドを呼び出します。
例:
3 つのタイプ「Person」、「Employee」、および「Manager」があります。 「Person」に対して定義された、人物の収入を計算する元のメソッド「income」があります。 人物はデフォルトで無職 (子供や退職者など) です。 したがって、 タイプ「Person」に対する「income」は、 常にゼロを戻します。 タイプ「Employee」およびタイプ「Manager」の場合、 収入を計算するには別のアルゴリズムを適用する必要があります。 そのため、「Employee」および「Manager」では、 「Person」に対するメソッド「income」がオーバーライドされます。
CREATE TABLE aTable (id integer, personColumn Person);
INSERT INTO aTable VALUES (0, Person()), (1, Employee()), (2, Manager()); $40000 以上の収入を得ている人物をリストします。
SELECT id, person, name
FROM aTable
WHERE person..income() >= 40000;タイプ「Person」に対するメソッド「income」は、 メソッド解決によって、最も具体的な適用可能許可メソッドとして選択されています。
- ルート・メソッドは「Person」に対する「income」自体です。
- 上記のアルゴリズムの 2 番目のステップが実行され、
一連のディスパッチ可能メソッドが構成されます。
- タイプ「Person」に対するメソッド「income」は、 最も具体的な適用可能許可メソッドなので、これは組み込まれます。
- タイプ「Employee」に対するメソッド「income」とタイプ「Manager」に対するメソッド「income」の両メソッドは、 ルート・メソッドをオーバーライドするもので、 「Employee」と「Manager」は「Person」のサブタイプなので、 これらのメソッドは組み込まれます。
したがって、 ディスパッチ可能メソッドのセットは、 {「Person」に対する「income」、「Employee」に対する「income」、「Manager」に対する「income」} です。
- 最も具体的なディスパッチ可能メソッドを決定します。
- 最も具体的なタイプが「Person」であるサブジェクトの場合:
- 初期の最も具体的なディスパッチ可能メソッドを、 タイプ「Person」に対する「income」にします。
- ディスパッチ可能メソッドのセットには、 「Person」の適切なサブタイプとサブジェクトの最も具体的なタイプのスーパータイプに対して定義された他のメソッドがないので、 「Person」に対する「income」が最も具体的なディスパッチ可能メソッドになります。
- 最も具体的なタイプが「Employee」であるサブジェクトの場合:
- 初期の最も具体的なディスパッチ可能メソッドを、 タイプ「Person」に対する「income」にします。
- 一連のディスパッチ可能メソッドごとに繰り返します。 タイプ「Employee」に対するメソッド「income」は、 「Person」の適切なサブタイプとサブジェクト (注: タイプはこの独自のスーパータイプとサブタイプである) の最も具体的なタイプのスーパータイプに対して定義されているので、 「Employee」に対するメソッド「income」が、 最も具体的なディスパッチ可能メソッドにより合致するメソッドになります。 タイプ「Employee」に対するメソッド「income」を最も適切なディスパッチ可能メソッドとしてこのステップを繰り返します。
- ディスパッチ可能メソッドのセットには、 「Employee」の適切なサブタイプおよびサブジェクトの最も具体的なタイプのスーパータイプに対して定義された他のメソッドがないので、 「Employee」に対するメソッド「income」が最も具体的なディスパッチ可能メソッドになります。
- 最も具体的なタイプが「Manager」であるサブジェクトの場合:
- 初期の最も具体的なディスパッチ可能メソッドを、 タイプ「Person」に対する「income」にします。
- 一連のディスパッチ可能メソッドごとに繰り返します。 タイプ「Manager」に対するメソッド「income」は、 「Person」の適切なサブタイプとサブジェクト (注: タイプはこの独自のスーパータイプとサブタイプである) の最も具体的なタイプのスーパータイプに対して定義されているので、「Manager」に対するメソッド「income」が、 最も具体的なディスパッチ可能メソッドにより合致するメソッドになります。 タイプ「Manager」に対するメソッド「income」を最も適切なディスパッチ可能メソッドとしてこのステップを繰り返します。
- ディスパッチ可能メソッドのセットには、 「Manager」の適切なサブタイプおよびサブジェクトの最も具体的なタイプのスーパータイプに対して定義された他のメソッドがないので、 「Manager」に対するメソッド「income」が最も具体的なディスパッチ可能メソッドになります。
- 最も具体的なタイプが「Person」であるサブジェクトの場合:
- 最も具体的なディスパッチ可能メソッドを呼び出します。