特定の関数の呼び出しに対して、データベース・マネージャーは、 同じ名前をもつ呼び出し可能な関数の中でどれが"最適"かを判別する必要があります。 これには、組み込み関数とユーザー定義関数の中から関数を解決する処理が含まれます。
引き数 とは、呼び出し時に関数に渡される値です。 SQL の中で呼び出されるとき、関数にはゼロ個以上の引き数のリストが渡されます。 このような引き数は、 引き数が引き数リストの位置によって決定されるという意味で定位置と言えます。 パラメーター は、関数への入力の形式的な定義です。 関数がデータベースに対して内部的に (組み込み関数) またはユーザーによって (ユーザー定義関数) 定義されるとき、 関数のパラメーターが (ゼロ個以上) 指定されます。 パラメーターの定義の順序がパラメーターの位置、 およびその結果としてパラメーターの意味を定義することになります。 したがって、どのパラメーターも関数の特定の定位置入力です。 呼び出し時に、引き数リスト中のその位置によって、引き数は特定のパラメーターに対応します。
データベース・マネージャーは、呼び出しで指定される関数名、 引き数の数とデータ・タイプ、SQL パスの中で同じ名前をもつすべての関数、 対応するパラメーターのデータ・タイプを使用して、 ある関数を選択するかどうかの判断基準とします。 関数を決定する過程で発生する可能性のある結果について以下に示します。
TEST.RISK(INTEGER) TEST.RISK(DOUBLE)
SQL パスには TEST スキーマが含まれており、 以下のように関数が参照されたとします (DB は DOUBLE 列)。
SELECT ... RISK(DB) ...
この場合は、2 番目の RISK が選択されます。
以下のように関数が参照される場合は (SI は SMALLINT 列)、
SELECT ... RISK(SI) ...
最初の RISK が選択されます。 これは、SMALLINT は INTEGER にプロモート可能であり、 優先順位リストでの順位がさらに下になる DOUBLE よりも一致性が高いためです (表 5 を参照)。
構造タイプである引き数について考慮する場合、優先順位リストには、 静的タイプの引き数のスーパータイプが含まれます。 最適なのは、構造タイプ階層の中で、 静的タイプの関数引き数に最も近いスーパータイプ・パラメーターで定義する関数です。
SELECT ... RISK(C) ...
この場合、引き数はどちらの RISK 関数のパラメーターとも整合性がありません。
TEST.RANDOM(INTEGER) PROD.RANDOM(INTEGER)
SQL パスは以下のとおりです。
"TEST","PROD"
この場合、次の関数参照では、
SELECT ... RANDOM(432) ...
TEST.RANDOM が選択されます。これは、 どちらの RANDOM 関数も同程度に高い一致性を示し (この例の場合は完全一致)、 どちらのスキーマも関数パスにありますが、 SQL パスにおいて TEST の方が PROD より先に指定されているためです。
引き数のデータ・タイプと、 対象とする関数のパラメーターに定義されているデータ・タイプとの比較は、 似たような名前の関数の中でどれが『最適』かを決定する基準となります。 関数の結果のデータ・タイプまたは関数のタイプ (列、スカラー、または表) は、 この決定には関係しないことに注意してください。
関数解決は、以下の手順で行われます。
ユーザー定義構造タイプ引き数に最適なのは、それ自体です。 次に適しているのは、すぐ上のスーパータイプです。このことは、 引き数の各スーパータイプに当てはまります。 ここで考慮しているのは、静的タイプ (宣言済みタイプ) の構造タイプ引き数であり、 動的タイプ (最も特定的なタイプ) ではありません。
組み込み関数は SYSIBM という名前の特殊なスキーマに含まれています。 SYSFUN スキーマにさらに別の使用可能な関数がありますが、 それらは組み込み関数とはみなされません。 それらはユーザー定義関数として開発されたものであり、 処理上の特別な考慮事項がないためです。 SYSIBM または SYSFUN スキーマに (あるいは "SYS" の文字で始まる名前のスキーマに)、 ユーザーがさらに関数を定義することはできません。
すでに説明したように、関数解決処理の中で、 組み込み関数はユーザー定義関数とまったく同じように扱われます。 関数解決の点で組み込み関数とユーザー定義関数の違いの 1 つは、 組み込み関数は関数解決で常に検討される必要があるということです。 したがって、パスから SYSIBM を省いても、 関数およびデータ・タイプの解決では SYSIBM がパスの最初のスキーマであることが想定されることになります。
たとえば、ユーザーの SQL パスが以下のように定義されているとします。
"SHAREFUN","SYSIBM","SYSFUN"
また、引き数の数とタイプが SYSIBM.LENGTH と同じである LENGTH 関数が SHAREFUN スキーマに定義されているとします。 この場合、このユーザーの SQL ステートメントで、 修飾なしで LENGTH を参照すると、
SHAREFUN.LENGTH が選択されます。 一方、ユーザーの SQL パスが以下のように定義されている場合には、
"SHAREFUN","SYSFUN"
同じ SHAREFUN.LENGTH 関数が存在していたとしても、 このユーザーの SQL ステートメントで修飾せずに LENGTH を参照すると、 SYSIBM.LENGTH が選択されることになります。 これは、SYSIBM がパスに指定されていないので、 暗黙のうちに SYSIBM が 1 番目のパスとなるためです。
このような状況では、以下の手段により、 発生の予想される問題を最小限にすることができます。
以下は、正常な関数解決の例を示しています。
3 つの異なるスキーマに 7 個の FOO 関数があり、 以下のように登録されているとします (必須キーワードの一部は省略されています)。
CREATE FUNCTION AUGUSTUS.FOO (CHAR(5), INT, DOUBLE) SPECIFIC FOO_1 ... CREATE FUNCTION AUGUSTUS.FOO (INT, INT, DOUBLE) SPECIFIC FOO_2 ... CREATE FUNCTION AUGUSTUS.FOO (INT, INT, DOUBLE, INT) SPECIFIC FOO_3 ... CREATE FUNCTION JULIUS.FOO (INT, DOUBLE, DOUBLE) SPECIFIC FOO_4 ... CREATE FUNCTION JULIUS.FOO (INT, INT, DOUBLE) SPECIFIC FOO_5 ... CREATE FUNCTION JULIUS.FOO (SMALLINT, INT, DOUBLE) SPECIFIC FOO_6 ... CREATE FUNCTION NERO.FOO (INT, INT, DEC(7,2)) SPECIFIC FOO_7 ...
以下のように関数が参照されるとします (I1 および I2 は INTEGER 列、 D は DECIMAL 列です)。
SELECT ... FOO(I1, I2, D) ...
この参照を行うアプリケーションの SQL パスが次のようになっているとします。
"JULIUS","AUGUSTUS","CAESAR"
この場合、アルゴリズムは次のようになります。
関数が選択された後も、いくつかの理由でその関数の使用が許可されない場合があります。 個々の関数は特定のデータ・タイプの結果を返すように定義されています。 この結果のデータ・タイプが、関数が呼び出される文脈と互換性がない場合、エラーが生じます。 たとえば、今度は結果のデータ・タイプが異なる STEP という名前の関数が次のように定義されているとします。
STEP(SMALLINT) returns CHAR(5) STEP(DOUBLE) returns INTEGER
以下のように関数が参照されると (S は SMALLINT 列)、
SELECT ... 3 + STEP(S) ...
引き数タイプが完全に一致しているため、最初の STEP が選択されます。 しかし、結果のタイプが加法演算子の引き数として求められる数値タイプではなく CHAR(5) であるため、 ステートメントではエラーになります。
この他にこの状態が起きる場合の例は次のとおりです。 いずれの例もステートメントのエラーが生じます。
関数呼び出しの引き数が、選択された関数のパラメーターのデータ・タイプと完全一致でない場合、 列への割り当てと同じ規則を適用して、 実行時に引き数がパラメーターのデータ・タイプに変換されます (割り当てと比較を参照)。 これには、引き数とパラメーターの間で精度、位取り、または長さが異なる場合も含まれます。