この項では、DB2 と UDF の間のインターフェースについて特定の詳細情報と、インターフェースを管理できるようにする sqludf.h インクルード・ファイルについて説明します。このインクルード・ファイルは C および C++ で作成された UDF にのみ適用されます。 Java による UDF のコーディングについては、Java UDF のコーディングを参照してください。
関数への DML 参照で指定される SQL 引き数に加えて、 DB2 は追加の引き数を外部 UDF に渡します。 C と C++ の場合、これらの引き数はすべて 『UDF への引き数の受け渡し』に示されている順序で渡されます。 Java UDF は、 SQL 引き数 と SQL 結果 引き数の 2 つの引き数のみを取りますが、他の方式を呼び出してそれ以外の情報にアクセスすることもできます。 Java UDF では、以降に説明する結果の SQL 状態 および診断メッセージ の引き数についても、同じ制限が課されます。 Java による UDF のコーディングについては、Java UDF のコーディングを参照してください。
引き数を UDF へ渡す構文 .--------------. V | >>-+----------------------+-----SQL-result---+------------------> | .----------------. | | V | | '----SQL-argument---+--' .------------------. V | >-----+--------------------------+-----SQL-result-ind---+-------> | .--------------------. | | V | | '----SQL-argument-ind---+--' >----SQL-state---function-name---specific-name------------------> >----diagnostic-message---+------------+---+-----------+--------> '-scratchpad-' '-call-type-' >----+--------+------------------------------------------------>< '-dbinfo-'
注: | 外部関数に渡される上記の各引き数は値へのポインターであり、実際の値ではありません。 |
以下に各引き数について説明します。
DB2 は、データ・タイプとサーバーのプラットフォームに応じて、 SQL-argument が表すデータの位置を調整します。
スカラー関数と表関数のどちらの場合でも、 DB2 はバッファーを割り振り、そのアドレスを UDF に渡します。 UDF はそれぞれの結果の値をバッファーに入れます。 DB2 は、データ・タイプで示される値を含むのに十分なバッファーを割り振ります。スカラー関数の場合、このデータ・タイプは、CAST FROM 文節があればそこで定義され、 CAST FROM 文節がなければ、RETURNS 文節で定義されます。表関数の場合、データ・タイプは、 RETURNS TABLE(...) 文節で定義されます。これらのデータ・タイプが C 言語構成にどのようにマップされるかについては、 SQL データ・タイプの UDF への受け渡し方法を参照してください。
表関数の場合、DB2 は、定義されているすべての列を DB2 に戻さなくてもよいように、パフォーマンス最適化を定義します。この機能を利用するように UDF を作成する場合、UDF は、表関数を参照しているステートメントが必要とする列のみを戻します。
たとえば、100 個の結果列が定義されている表関数の CREATE FUNCTION ステートメントを考えてみましょう。この関数を参照するステートメントに関係するものが、これらの結果列のうちの 2 つだけであるならば、この最適化により、UDF は各行にこれらの 2 つの列だけを戻し、他の 98 列には時間を費やしません。この最適化の詳細については、後で説明する DB 情報 引き数を参照してください。
戻される各値については (つまり、スカラー関数の場合は単一の値、また一般に、表関数の場合は複数の値について)、UDF コードが、結果のデータ・タイプと長さに必要なバイト数よりも多くのバイトを戻さないようにしてください。 DB2 は、UDF 本体が結果バッファーの上限より数バイト多く書き込んだかどうかを判別しようとし、 SQLCODE -450 (SQLSTATE 39501) を戻します。ただし、DB2 により検出されない、UDF による大幅な上書きは、予期しない結果や異常終了になる可能性があります。
DB2 は、データ・タイプとサーバーのプラットフォームに応じて、 SQL-result が表すデータの位置を調整します。
関数を NOT NULL CALL で定義すると、UDF 本体はヌル値に対する検査を行う必要がありません。ただし、NULL CALL で定義されると引き数はヌルとなる可能性があるため、 UDF はその検査を行う必要があります。
標識は SMALLINT 値の形式をとります。これは、SQL データ・タイプの UDF への受け渡し方法で説明するように UDF で定義することができます。 DB2 は、データ・タイプとサーバーのプラットフォームに応じて、 SQL-argument-ind が表すデータの位置を調整します。
UDF は、この引き数を使用して特定の結果値がヌルかどうかを示します。
以下の場合に、DB2 は関数結果をヌル (-2) として扱います。
これは、関数を NOT NULL CALL オプションで定義した場合にも当てはまります。
関数を NOT NULL CALL で定義した場合でも、UDF 本体は結果の標識を設定しなければなりません。たとえば、分母がゼロである場合、除算関数は結果をヌルに設定することができます。
標識は SMALLINT 値の形式をとります。これは、SQL データ・タイプの UDF への受け渡し方法で説明するように UDF で定義することができます。
RESULT 列リストを用いた表関数最適化が UDF により使用されている場合、必要な列に対応する標識のみを設定する必要があります。
DB2 は、データ・タイプとサーバーのプラットフォームに応じて、 SQL-result-ind が表すデータの位置を調整します。
その他の値はエラー状態として扱われ、その結果 SQLCODE -463 (SQLSTATE 39001) が発生します。
渡される関数名の形式は以下のとおりです。
<schema-name>.<function-name>
各部分はピリオドで区切られます。以下に例を 2 つ示します。
PABLO.BLOOP WILLIE.FINDSTRING
この形式を使うと、複数の外部関数に同じ UDF 本体を使用してもその呼び出し時にはそれらの関数を区別することができます。
注: | オブジェクト名およびスキーマ名にはピリオドを付けることができますが、付けない方がよいでしょう。たとえば、関数 rotate がスキーマ obj.op の中にあり、戻される関数名が obj.op.rotate の場合、スキーマ名が obj なのか obj.op なのかがはっきりしません。 |
willie_find_feb99 SQL9904281052440430
この例の最初の値は、ユーザーが CREATE FUNCTION ステートメントで定義します。 2 番目の値は、ユーザーが値を指定しなかった場合に DB2 によって現行タイム・スタンプから生成される値です。
上述した SQL-state 引き数を用いて UDF がエラーまたは警告のいずれかを戻す場合、ここには記述情報を組み込むことができます。 DB2 はこの情報をトークンとしてメッセージ内に組み込みます。
DB2 は、UDF を呼び出す前に最初の文字をヌルに設定します。 DB2 は、戻り時にそのストリングを C の NULL 終了ストリングとして扱います。このストリングは、エラー状態のトークンとして SQLCA 内に組み込まれます。このストリングの少なくとも最初の一部は、 SQLCA または DB2 CLP メッセージに表示されます。ただし、表示される実際の文字数は、その他のトークンの長さにより決まります。これは、DB2 がトークンを切り捨てて、 SQLCA によって指定された合計トークン長の制限に合わせることがあるからです。 X'FF' という文字は、SQLCA のトークンを区切るために使用するので、テキスト内には使用しないでください。
UDF コードは、そのコードに渡される VARCHAR(70) バッファーに入らないほど多くのテキストを戻すべきではありません。 DB2 は、UDF 本体がこのバッファーの上限を超えて定義されたかどうかを、文字 SQLCODE -450 (SQLSTATE 39501) により判別しようとします。ただし、UDF が上書きされると、予測不可能な結果や異常終了を引き起こして DB2 により検出されない場合があります。
DB2 では、UDF から DB2 に戻されるメッセージ・トークンがデータベースと同じコード・ページにあることを前提とします。使用している UDF がこの場合に当てはまるかどうかを確認してください。 7 ビットの不変の ASCII サブセットを使うと、 UDF はメッセージ・トークンを任意のコード・ページに戻します。
スカラー関数の場合、スクラッチパッドは最初の呼び出し前に初期化され、その後は通常 DB2 による参照や修正を行うことはできません。
表関数の場合、FINAL CALL が CREATE FUNCTION で指定されているなら、スクラッチパッドは UDF への FIRST 呼び出しより前に上記のように初期化されます。この呼び出しの後、スクラッチパッドの内容は、完全に表関数の制御下に置かれます。
NO FINAL CALL が指定されなかったか、または表関数の省略時値が使用された場合、スクラッチパッドは各 OPEN 呼び出しごとに上記のように初期化され、スクラッチパッドの内容は完全に OPEN 呼び出しの合間に表関数の制御下に置かれます。 (これは、結合または副照会で使用される表関数ではかなり重要である場合があります。 OPEN 呼び出しの合間にスクラッチパッドの内容を保守する必要がある場合、 CREATE FUNCTION ステートメントで FINAL CALL を指定しなければなりません。通常の OPEN、FETCH、および CLOSE 呼び出しに加え、FINAL CALL を指定すると、表関数は、スクラッチパッド保守およびリソース解放のために、 FIRST および FINAL 呼び出しも受け取ります。)
スクラッチパッドは、CLOB か BLOB と同じタイプを使って UDF にマップすることができます。これは、渡される引き数が同じ構造であるためです。詳細については、SQL データ・タイプの UDF への受け渡し方法を参照してください。
UDF コードがスクラッチパッド・バッファーの外側で変更を行わないことを確認してください。 DB2 は、UDF 本体がこのバッファーの上限を超えて定義されたかどうかを、文字 SQLCODE -450 (SQLSTATE 39501) により判別しようとしますが、 UDF が大幅に上書きされると予測不可能な結果や異常終了を引き起こし、その結果 DB2 がエラーを出さないこともあります。
スクラッチパッドを使用するスカラー UDF が副照会で参照される場合、 DB2 は副照会の呼び出しの合間にスクラッチパッドをリフレッシュすることに決めることがあります。 UDF で FINAL CALL が指定されている場合、このリフレッシュは、最終呼び出し が行われた後に起こります。
DB2 は、データ・フィールドの位置がどのデータ・タイプの記憶域でも合うよう、スクラッチパッドを初期化します。その結果、スクラッチパッド構造の一部または全体 (長さフィールドを含む) が正しく位置合わせされない場合があります。スクラッチパッドの宣言およびそれへのアクセスに関する詳細については、 32 ビット・プラットフォームおよび 64 ビット・プラットフォームでのスクラッチパッドの作成を参照してください。
現在使用可能なすべての値が以下にリストされていますが、 "A ならば AA を実行、さもなければ B ならば BB を実行、さもなければ必ず C なので CC を実行 (if A do AA, else if B do BB, else it must be C so do CC)" といったタイプの論理ではなく、予期されるすべての値を明示的にテストする切り替えまたは CASE ステートメントを UDF に含める必要があります。これは、将来付加的な呼び出しタイプを追加できるようにするため、および明示的に条件 C をテストしない場合には、新しい条件が追加されると問題が発生するからです。
注:
スカラー関数の場合、 呼び出しタイプ (call-type) には次のものが含まれます。
SCRATCHPAD が指定されていても FINAL CALL が指定されていない場合、 UDF は最初の呼び出しを識別するためにこの呼び出しタイプ引き数を使用しないことに注意してください。その代わり、スクラッチパッドのすべてゼロの状態に依存する必要があります。
リソースの解放
スカラー UDF は、たとえばメモリーのような、必要なリソースを解放することになります。 SCRATCHPAD も指定され、リソースを追跡するために使用される場合は、 FINAL CALL が UDF に指定されている場合には、FINAL 呼び出しがリソースを解放するのが自然です。 FINAL CALL が指定されていない場合には、獲得されたいずれかのリソースをその同じ呼び出し時に解放する必要があります。
表関数の場合、 呼び出しタイプ (call-type) には次のものがあります。
結合や副照会が含まれている場合、 OPEN/FETCH.../CLOSE 呼び出しはステートメントの実行内で繰り返すことができますが、 FIRST 呼び出しと FINAL 呼び出しはそれぞれ 1 回ずつしか実行できません。 FIRST 呼び出しと FINAL 呼び出しが現れるのは、表関数に対して FINAL CALL が指定される場合だけです。
リソースの解放
獲得したリソースを解放する UDF を作成します。表関数の場合、CLOSE 呼び出しと FINAL 呼び出しの 2 つで通常この解放を行うことができます。 CLOSE 呼び出しは、OPEN 呼び出しと対になり、ステートメントの実行内で複数回実行することができます。 FINAL 呼び出しが行われるのは、UDF に FINAL CALL が指定される場合だけで、ステートメントにつき 1 回です。
UDF のすべての OPEN/FETCH/CLOSE の組に 1 つのリソースを適用できる場合、 FIRST 呼び出し時にこのリソースを獲得し、FINAL 呼び出し時にそれを解放する UDF を作成します。スクラッチパッドが通常このリソースを追跡します。表関数では、FINAL CALL が指定される場合、スクラッチパッドが初期化されるのは FIRST 呼び出しの前だけです。 FINAL CALL が指定されていない場合には、各 OPEN 呼び出しの前に再初期化されます。
リソースがそれぞれの OPEN/FETCH/CLOSE の組に対して固有である場合には、 CLOSE 呼び出し時にリソースを解放する UDF を作成します。 (表関数が副照会または結合関数中にある場合、 DB2 最適化プログラムがステートメントの実行を編成する方法に応じて、 OPEN/FETCH/CLOSE の組が複数回指定される可能性が高いことに注意してください。)
現在接続されているデータベースの名前。このフィールドは、128 文字の長識別子です。上述のデータベース名の長さ フィールドは、このフィールドの実際の長さを示します。ヌル終了符や埋め込みは含まれません。
アプリケーション実行時許可 ID。このフィールドは、128 文字の長識別子です。ヌル終了符や埋め込みは含まれません。上述のアプリケーション許可 ID の長さ フィールドは、このフィールドの実際の長さを示します。
2 つの 48 バイト長の構造が合併したもので、1 つは DB2 ユニバーサル・データベースが使用し、もう 1 つは将来の使用のために予約されています。 DB2 ユニバーサル・データベースが使用する構造には、以下のフィールドがあります。
後に挙げる表名 のスキーマ。このフィールドは、128 文字の長識別子です。ヌル終了符や埋め込みは含まれません。上述のスキーマ名の長さ フィールドは、このフィールドの実際の長さを示します。
後に挙げる表名 の長さ。表名が渡されない場合は 0 (ゼロ) が入ります。このフィールドは無符号短整数です。
更新中または挿入中の表の名前です。このフィールドが設定されるのは、 UDF 参照が UPDATE ステートメントで SET 文節の右側にあるか、 INSERT ステートメントの VALUES リスト内の項目になっている場合だけです。このフィールドは、128 文字の長識別子です。ヌル終了符や埋め込みは含まれません。上述の表名の長さ フィールドは、このフィールドの実際の長さを示します。 スキーマ名 とこのフィールドが合わさって、完全修飾表名になります。
表名の場合とまったく同じ条件の下では、このフィールドには更新中または挿入中の列の名前が入ります。それ以外の場合は、予想できません。このフィールドは、128 文字の長識別子です。ヌル終了符や埋め込みは含まれません。上述の列名の長さ フィールドは、このフィールドの実際の長さを示します。
8 文字のフィールドで、製品およびそのバージョン、リリース、修正レベルを、 pppvvrrm の書式で識別します。この書式は次のとおりです。
アプリケーション・サーバーのオペレーティング・プラットフォームは、以下のとおりです。
後に挙げる表関数列リスト フィールドで指定された表関数列リストにある非ゼロ項目の数。
これが表関数である場合、このフィールドは、DB2 が動的に割り振った短整数の配列へのポインターです。これがスカラー関数である場合、このポインターはヌルです。
このフィールドは表関数にのみ使用されます。最初の n 個の項目 (n は、 表関数列リストの項目の数 (number of table function column list) フィールドで指定される)、 numtfcol のみが関係します。 n は 0 のこともありますが、いずれにしても、CREATE FUNCTION ステートメントの RETURNS TABLE(...) 文節内の関数に定義される結果列の数以下になります。これらの値は、このステートメントが表関数から取得する必要のある列の序数に対応します。値が '1' の場合は最初に定義された結果列を表し、 '2' の場合は 2 番目に定義された結果列を表し、 3 番目以降も同様です。値は任意の順序にすることができます。 n はゼロのこともあります。 SELECT COUNT(*) FROM TABLE(TF(...)) AS QQ に類似したステートメント (ただし実際の列値は照会には必要ない) の場合、変数 numtfcol がゼロになることがあるからです。
この配列は、最適化の機会を表します。 UDF は、表関数のすべての結果列のすべての値を戻す必要はなく、特定の文脈で必要なものだけを戻します。戻されるのは、配列で (番号によって) 識別される列です。この最適化は、パフォーマンスを向上させるために UDF 論理を複雑にする場合があるので、 UDF では、定義されたすべての列を戻すように選択することができます。
このフィールドは、ヌル文字で終了する C のストリングを指すポインターで、アプリケーションの DB2 への接続を一意的に識別します。このフィールドは、データベースに接続するたびに再生成されます。
ストリングの最大長は 32 文字で、その形式は、クライアントと DB2 の間で設定された接続タイプによって決まります。通常は以下のような形式です。
<x>.<y>.<ts>
ここで、<x> と <y> は接続タイプに応じて変わりますが、 <ts> は YYMMDDHHMMSS という形式の 12 文字のタイム・スタンプで、固有性を確実にするために DB2 によって調整されることがあります。
Example: *LOCAL.db2inst.980707130144
このフィールドは将来の利用のためのものです。 20 文字の長さに定義されています。
次に、上記の引き数について要約し、それらを DB2 と外部 UDF 間のインターフェースでどのように使用するのかを説明します。
スカラー関数の場合、引き数は次のとおりです。
関数参照で識別された値を DB2 から UDF に渡します。各 SQL 引き数ごとに 1 つあります。
UDF により生成された結果値を、DB2 および関数参照が行われた SQL ステートメントに渡します。
この変数の位置は SQL 引き数 に対応し、特定の引き数がヌルであるかどうかを UDF に知らせます。各 SQL 引き数 ごとに 1 つあります。
UDF は、この引き数を使用して、 SQL 結果 の関数結果にヌルが入っているかどうかを DB2 に報告します。
UDF は、この引き数を使用して、例外情報を DB2 に送ります。
DB2 は、この引き数を使用して、参照されている関数が何であるかを UDF に伝えます。
DB2 は、この引き数を使用して、呼び出しの合間の UDF 状態の保存を管理します。 スクラッチパッド (scratchpad) は、 DB2 により作成および初期化された後 UDF により管理されます。 DB2 は、呼び出しタイプ (call-type) 引き数を使って呼び出しのタイプを UDF に知らせます。
DB2 によって UDF に渡される構造で、追加情報を含みます。
表関数は論理的には参照元の SQL ステートメントに表を戻しますが、 DB2 と表関数の間の物理インターフェースは行単位です。表関数の場合、引き数は次のとおりです。
関数参照で識別された値を DB2 から UDF に渡します。この引き数は、FETCH 呼び出しに対して、 OPEN 呼び出しと FIRST 呼び出しの場合と同じ値を持ちます。各 SQL 引き数に 1 つあります。
UDF によって戻されている行の個々の列値を戻すのに使用されます。 CREATE FUNCTION ステートメントの RETURNS TABLE (...) 文節で定義される結果列の値ごとに、いずれかの引き数があります。
この引き数の位置付けは SQL 引き数 (SQL-argument) 値に対応し、特定の引き数がヌルであるかどうかを UDF に知らせます。各 SQL 引き数に 1 つあります。
UDF は、この引き数を使用して、表関数の出力行で戻された個々の列値がヌルであるかどうかを DB2 に報告します。この引き数の位置は、SQL 結果 (SQL-result) 引き数に対応します。
UDF は、この引き数を使用して、例外情報と end-of-table (表の終わり) 条件を DB2 に送ります。
DB2 は、この引き数を使用して、参照されている関数が何であるかを UDF に伝えます。
DB2 は、この引き数を使用して、呼び出しの合間の UDF 状態の保存を管理します。 スクラッチパッド (scratchpad) は、 DB2 により作成および初期化された後 UDF により管理されます。 DB2 は、呼び出しタイプ (call-type) 引き数を使って呼び出しのタイプを UDF に知らせます。表関数の場合、これらの呼び出しタイプは OPEN、FETCH、CLOSE で、任意選択で FIRST と FINAL にすることもできます。
DB2 によって UDF に渡される構造で、追加情報を含みます。
UDF、SQL 結果、SQL 結果標識、および SQL 状態 の通常の値出力は、 DB2 から UDF に渡される引き数を使って DB2 に戻されることに注意してください。 UDF は、関数の意味では何も戻さないように定義されています (つまり、関数の戻りタイプは void です)。次の例の void 定義と return ステートメントを参照してください。
#include ... void SQL_API_FN divid( ... arguments ... ) { ... UDF body ... return; }
上記の例で、SQL_API_FN は、サポートされるオペレーティング・システムごとに異なる関数の呼び出し規則を指定するマクロです。このマクロは、ストアード・プロシージャーや UDF を作成する場合に必要です。
UDF のプログラミング例については、UDF コードの例を参照してください。
この項では、UDF パラメーターと結果の両方に有効なタイプを識別し、対応する引き数を C や C++ 言語の UDF で定義する方法をそれぞれ指定します。 Java UDF の型定義については、Java でサポートされている SQL データ・タイプを参照してください。 sqludf.h インクルード・ファイルとそこで定義されるタイプを使用すると、さまざまなデータ・タイプおよびコンパイラーに当てはまる言語変数および構造を自動的に生成できます。たとえば、BIGINT では、SQLUDF_BIGINT データ・タイプを使用して、異なるコンパイラー間での 64 ビットの整数型の名前の違いを隠すことができます。このインクルード・ファイルについては、UDF インクルード・ファイル: sqludf.h で説明しています。
これは、引き数値の書式を管理する CREATE FUNCTION ステートメントで定義される各関数パラメーターのデータ・タイプです。引き数のデータ・タイプからのプロモーションは、この書式でデータを受け取る必要はありません。 DB2 は、引き数値に対してこのようなプロモーションを自動的に実行します。引き数のプロモーションについては、SQL 解説書 で説明されています。
関数結果の場合、書式を定義する CREATE FUNCTION ステートメントの CAST FROM 文節で指定されるデータ・タイプとなります。 CAST FROM 文節がない場合は、RETURNS 文節で指定されるデータ・タイプが書式を定義します。
以下の例での CAST FROM 文節は、UDF 本体が SMALLINT を戻し、 DB2 がその値を関数参照を行うステートメントに渡す前に INTEGER にキャストすることを意味します。
... RETURNS INTEGER CAST FROM SMALLINT ...
この場合、UDF は以下に示すように SMALLINT を生成するように定義しなければなりません。 CAST FROM データ・タイプは RETURNS データ・タイプに対してキャスト可能 でなければならないため、任意に他のデータ・タイプを選ぶことはできません。データ・タイプ間のキャストについては、 SQL 解説書 で説明されています。
以下に、SQL タイプとその C 言語での表示を示します。 Java の SQL タイプ表記のリストについては、 Java でサポートされている SQL データ・タイプを参照してください。また、それぞれのタイプがパラメーターや結果として有効かどうかを説明します。さらに、そのタイプを C や C++ 言語の UDF で定義される引き数として表した例も示します。
正しい例。 C で short として表します。
整数の UDF パラメーターを定義する際は、SMALLINT ではなく INTEGER を使用するようにしてください。これは、DB2 が SMALLINT 引き数を INTEGER にプロモートしないためです。たとえば、UDF を次のように定義するとします。
CREATE FUNCTION SIMPLE(SMALLINT)...
以下に例を示します。
short *arg1; /* example for SMALLINT */ short *arg1_null_ind; /* example for any null indicator */
INTEGER データ (... SIMPLE(1)...) を使用して SIMPLE 関数を呼び出すと、関数が見つからないことを示す SQLCODE -440 (SQLSTATE 42884) エラーが出されますが、この関数のエンド・ユーザーはそのメッセージの原因を理解できないことがあります。上の例で 1 は INTEGER であるため、それを SMALLINT にキャストすることも INTEGER としてパラメーターを定義することもできます。
正しい例。 C で sqlint32 として表します。 DB2 インクルード・ファイル sqlsystm.h は、このタイプを各プラットフォームに合った 32 ビットの整数として定義します。
以下に例を示します。
sqlint32 *arg2; /* example for INTEGER */
正しい例。 C で sqlint64 として表します。
以下に例を示します。
sqlint64 *arg3; /* example for INTEGER */
DB2 では、sqlint64 C 言語タイプが定義されるので、コンパイラーとオペレーティング・システムの 64 ビットの符号付き整数の定義の違いはなくなります。 #include sqludf.h を指定して、定義を選出する必要があります。
誤った例。これは C 言語の表記ではありません。 10 進数の値を渡したい場合は、パラメーターを DECIMAL からキャスト可能なデータ・タイプ (CHAR や DOUBLE など) に定義して、引き数をこのタイプに明示的にキャストしなければなりません。 DOUBLE の場合は、DB2 が自動的にプロモーションするので、 10 進値引き数を明示的に DOUBLE パラメーターにキャストする必要はありません。
DECIMAL(5,2) の WAGE と、DECIMAL(4,1) の HOURS という 2 つの列があり、賃金、労働時間、および他の要素に基づいて週給を計算するとします。 UDF は次のようになります。
CREATE FUNCTION WEEKLY_PAY (DOUBLE, DOUBLE, ...) RETURNS DECIMAL(7,2) CAST FROM DOUBLE ...;
上記の UDF では、最初の 2 つのパラメーターは賃金と時間に当たります。次のように SQL 選択ステートメントで UDF WEEKLY_PAY を呼び出します。
SELECT WEEKLY_PAY (WAGE, HOURS, ...) ...;
DECIMAL 引き数は DOUBLE にキャスト可能なので、明示的にキャストする必要はありません。
別の方法として、CHAR 引き数を持つ WEEKLY_PAY を次のように定義できます。
CREATE FUNCTION WEEKLY_PAY (VARCHAR(6), VARCHAR(5), ...) RETURNS DECIMAL (7,2) CAST FROM VARCHAR(10) ...;
これは、次のように呼び出します。
SELECT WEEKLY_PAY (CHAR(WAGE), CHAR(HOURS), ...) ...;
DECIMAL 引き数は VARCHAR にプロモーションできないので、明示的にキャストすることが必要であることに注意してください。
浮動小数点パラメーターを使用する利点は、 UDF 内の値に算術計算を実行しやすくなるということです。一方、文字パラメーターを使用する利点は、正確に 10 進数の値を表すことが常に可能であるということです。浮動小数点の場合、これは常に可能というわけではありません。
正しい例。 C で float として表します。
以下に例を示します。
float *result; /* example for REAL */
正しい例。 C で double として表します。
以下に例を示します。
double *result; /* example for DOUBLE */
正しい例。 C では char...[n+1] として表します (これは、C の NULL 終了ストリングなので、最後の文字はヌルつまり X'00' です)。
以下に例を示します。
char arg1[14]; /* example for CHAR(13) */ char *arg1; /* also perfectly acceptable */
CHAR(n) パラメーターの場合、DB2 は常にデータの n バイトをバッファーに移動し、 n+1 バイトをヌルに設定します。 RETURNS CHAR(n) 値の場合、DB2 は常に n バイトを受け取り、 n+1 バイトを無視します。この場合は、最初の n 文字にヌル文字を誤って含めないように注意してください。そうしないと、DB2 はデータの通常部分としてのみこの文字を認識し、後になって外見的に異例の結果を生じることがあります。
FOR BIT DATA が指定されている場合、 UDF 内で関数を処理する通常の C ストリングを使用する際は注意してください。これらの関数の多くはストリングの区切り文字としてヌルを探すので、ヌル文字 (X'00') がデータ値の中にあっても正しいことになります。
文字の UDF パラメーターを定義する際は、CHAR よりも VARCHAR を使用するようにしてください。これは、DB2 が VARCHAR 引き数を CHAR にプロモートしないためです。たとえば、UDF を次のように定義するとします。
CREATE FUNCTION SIMPLE(INT,CHAR(1))...
VARCHAR データ (... SIMPLE(1,'A')...) を使用して SIMPLE 関数を呼び出すと、関数が見つからないことを示す SQLCODE -440 (SQLSTATE 42884) エラーが出されますが、この関数のエンド・ユーザーはそのメッセージの原因を理解できないことがあります。上の例で、'A' は VARCHAR であるため、それを CHAR にキャストすることも VARCHAR としてパラメーターを定義することもできます。
正しい例。 C で次のような構造として表します。
struct sqludf_vc_fbd { unsigned short length; /* length of data */ char data[1]; /* first char of data */ };
[1] は、単にコンパイラーに対する配列を示しています。 1 文字だけが渡されることを意味しているのではありません。すなわち構造のアドレスが渡されますが、それは実際の構造ではないため、配列論理を使用する方法を提供するだけです。
これらの値は、C の NULL 終了ストリングとしては表されません。これは、ヌル文字がデータ値の一部として正しく認識されることがあるためです。その長さは、構造変数 length を使用して UDF にパラメーターとして正しく渡されます。 RETURNS 文節の場合、UDF に渡される長さはバッファーの長さです。 UDF 本体は、構造変数 length を使ってデータ値の実際の長さを戻す必要があります。
以下に例を示します。
struct sqludf_vc_fbd *arg1; /* example for VARCHAR(n) FOR BIT DATA */ struct sqludf_vc_fbd *result; /* also for LONG VARCHAR FOR BIT DATA */
正しい例。 C で char...[n+1] として表します。 (これは C の NULL 終了ストリングです。)
VARCHAR(n) パラメーターの場合、DB2 はヌルを (k+1) の位置に置きます。この場合の k は個々に発生する長さです。このため、C ストリング処理関数はこれらの値の操作に適しています。 RETURNS VARCHAR(n) 値の場合、UDF 本体は実際の値をヌルを使って区切る必要があります。これは、DB2 がこのヌル文字から結果の長さを決めるためです。
以下に例を示します。
char arg2[51]; /* example for VARCHAR(50) */ char *result; /* also perfectly acceptable */
正しい例。 C で sqldbchar[n+1] として表します。 (これは NULL 終了グラフィック・ストリングです)。 wchar_t が長さ 2 バイトとして定義されているプラットフォーム上では、 wchar_t[n+1] を使用できますが、 sqldbchar を使用することをお勧めします。これら 2 つのデータ・タイプの詳細については、C および C++ での wchar_t または sqldbchar データ・タイプの選択を参照してください。
GRAPHIC(n) パラメーターの場合、DB2 は n 個の 2 バイト文字をバッファーに移動し、次の 2 バイトをヌルに設定します。 DB2 から UDF に渡されるデータは DBCS 書式であり、戻される結果も DBCS 書式であるとみなされます。この動作は、C および C++ での WCHARTYPE プリコンパイラー・オプションで説明する WCHARTYPE NOCONVERT プリコンパイラー・オプションを使うことと同じです。 RETURNS GRAPHIC(n) 値の場合、DB2 は常に n 個の 2 バイト文字を受け取り、それ以降のバイトを無視します。
グラフィック UDF パラメーターを定義する際は、GRAPHIC よりも VARGRAPHIC を使用するようにしてください。これは、DB2 が VARGRAPHIC 引き数を GRAPHIC にプロモートしないためです。たとえば、UDF を次のように定義するとします。
CREATE FUNCTION SIMPLE(GRAPHIC)...
VARGRAPHIC データ (... SIMPLE('graphic_literal')...) を使用して SIMPLE 関数を呼び出すと、関数が見つからないことを示す SQLCODE -440 (SQLSTATE 42884) エラーが出されますが、この関数のエンド・ユーザーはそのメッセージの原因を理解できないことがあります。上の例で、graphic_literal は VARGRAPHIC データとして解釈されるリテラル DBCSであるため、それを GRAPHIC にキャストすることも VARGRAPHIC としてパラメーターを定義することもできます。
以下に例を示します。
sqldbchar arg1[14]; /* example for GRAPHIC(13) */ sqldbchar *arg1; /* also perfectly acceptable */
正しい例。 C で sqldbchar[n+1] として表します。 (これは NULL 終了グラフィック・ストリングです)。 wchar_t が長さ 2 バイトとして定義されているプラットフォーム上では、 wchar_t[n+1] を使用できますが、 sqldbchar を使用することをお勧めします。これら 2 つのデータ・タイプの詳細については、C および C++ での wchar_t または sqldbchar データ・タイプの選択を参照してください。
VARGRAPHIC(n) パラメーターの場合、 DB2 はグラフィック・ヌルを (k+1) の位置に置きます。この場合の k は個々に発生する長さです。グラフィック・ヌルは、グラフィック・ストリングの最後の文字の全バイトに 2 進ゼロ ('\0's) が含まれていることを示します。 DB2 から UDF に渡されるデータは DBCS 書式であり、戻される結果も DBCS 書式であるとみなされます。この動作は、C および C++ での WCHARTYPE プリコンパイラー・オプションで説明する WCHARTYPE NOCONVERT プリコンパイラー・オプションを使うことと同じです。 RETURNS VARGRAPHIC(n) 値の場合、 UDF 本体は実際の値をグラフィック・ヌルを使って区切る必要があります。これは、DB2 がこのグラフィック・ヌル文字から結果の長さを決めるためです。
以下に例を示します。
sqldbchar args[51], /* example for VARGRAPHIC(50) */ sqldbchar *result, /* also perfectly acceptable */
正しい例。 C で次のような構造として表します。
struct sqludf_vg { unsigned short length; /* length of data */ sqldbchar data[1]; /* first char of data */ };
wchar_t が長さ 2 バイトとして定義されているプラットフォームでは、上記の例の sqldbchar の箇所に wchar_t を使用できますが、 sqldbchar の方を使用するようお勧めします。これら 2 つのデータ・タイプの詳細については、C および C++ での wchar_t または sqldbchar データ・タイプの選択を参照してください。
[1] は、単にコンパイラーに対する配列を示しています。グラフィック文字を 1 つだけ渡すことを意味しているのではありません。すなわち、渡されるのは構造のアドレスであり、実際の構造ではないため、配列論理を使用する方法が提供されることになります。
これらは NULL 終了グラフィック・ストリングとしては表されません。その長さ (2 バイト文字単位) は、構造変数 length を使用して UDF にパラメーターとして明示的に渡されます。 DB2 から UDF に渡されるデータは DBCS 書式であり、戻される結果も DBCS 書式であるとみなされます。この動作は、C および C++ での WCHARTYPE プリコンパイラー・オプションで説明する WCHARTYPE NOCONVERT プリコンパイラー・オプションを使うことと同じです。 RETURNS 文節の場合、UDF に渡される長さはバッファーの長さです。 UDF 本体は、構造変数 length を使ってデータ値の実際の長さを 2 バイト文字で戻す必要があります。
以下に例を示します。
struct sqludf_vg *arg1; /* example for VARGRAPHIC(n) */ struct sqludf_vg *result; /* also for LONG VARGRAPHIC */
正しい例。 C で CHAR(10) として、つまり char...[11] として表します。日付の値は、常に ISO 書式 yyyy-mm-dd で UDF に渡されます。
以下に例を示します。
char arg1[11]; /* example for DATE */ char *result; /* also perfectly acceptable */
正しい例。 C で CHAR(8) として、つまり char...[9] として表します。時間の値は、常に ISO 書式 hh.mm.ss で UDF に渡されます。
以下に例を示します。
char *arg; /* example for DATE */ char result[9]; /* also perfectly acceptable */
正しい例。 C で CHAR(8) として、つまり char...[27] として表します。タイム・スタンプの値は、常に yyyy-mm-dd-hh.mm.ss.nnnnnn 書式で渡されます。
以下に例を示します。
char arg1[27]; /* example for TIMESTAMP */ char *result; /* also perfectly acceptable */
正しい例。 C で次のような構造として表します。
struct sqludf_lob { sqluint32 length; /* length in bytes */ char data[1]; /* first byte of lob */ };
[1] は、単にコンパイラーに対する配列を示しています。 1 文字だけが渡されることを意味しているのではありません。すなわち構造のアドレスが渡されますが、それは実際の構造ではないため、配列論理を使用する方法を提供するだけです。
これらは C の NULL 終了ストリングとして表されません。その長さは、構造変数 length を使用して UDF にパラメーターとして正しく渡されます。 RETURNS 文節の場合、UDF に戻される長さはバッファーの長さです。 UDF 本体は、構造変数 length を使ってデータ値の実際の長さを戻す必要があります。
以下に例を示します。
struct sqludf_lob *arg1; /* example for BLOB(n), CLOB(n) */ struct sqludf_lob *result;
正しい例。 C で次のような構造として表します。
struct sqludf_lob { sqluint32 length; /* length in graphic characters */ sqldbchar data[1]; /* first byte of lob */ };
wchar_t が長さ 2 バイトとして定義されているプラットフォームでは、上記の例の sqldbchar の箇所に wchar_t を使用できますが、 sqldbchar の方を使用するようお勧めします。これら 2 つのデータ・タイプの詳細については、C および C++ での wchar_t または sqldbchar データ・タイプの選択を参照してください。
[1] は、単にコンパイラーに対する配列を示しています。グラフィック文字を 1 つだけ渡すことを意味しているのではありません。すなわち、構造のアドレスが渡されますが、それは実際の構造ではないため、配列論理を使用する方法を提供するだけです。
これらは NULL 終了グラフィック・ストリングとしては表されません。その長さは、構造変数 length を使用して UDF にパラメーターとして正しく渡されます。 DB2 から UDF に渡されるデータは DBCS 書式であり、戻される結果も DBCS 書式であるとみなされます。この動作は、C および C++ での WCHARTYPE プリコンパイラー・オプションで説明する WCHARTYPE NOCONVERT プリコンパイラー・オプションを使うことと同じです。 RETURNS 文節の場合、UDF に渡される長さはバッファーの長さです。 UDF 本体は、構造変数 length を使ってデータ値の実際の長さを戻す必要がありますが、その際にこれらすべての長さを 2 バイト文字で表していなければなりません。
以下に例を示します。
struct sqludf_lob *arg1; /* example for DBCLOB(n) */ struct sqludf_lob *result;
正しい例または誤った例 (基本タイプにより異なる)。特殊タイプは、UDF の基本タイプの書式で UDF に渡されるため、基本タイプが有効な場合に限り指定されます。
以下に例を示します。
struct sqludf_lob *arg1; /* for distinct type based on BLOB(n) */ double *arg2; /* for distinct type based on DOUBLE */ char res[5]; /* for distinct type based on CHAR(4) */
AS LOCATOR タイプ修飾子は、UDF のパラメーター定義および結果定義においてのみ有効です。これは、LOB タイプか、LOB タイプに基づく特殊タイプを修正する場合にのみ使用できます。このタイプ修飾子を指定すると、UDF には LOB 値全体ではなく 4 バイトのロケーターが渡されます。
以下に例を示します。
sqludf_locator *arg1; /* locator argument */ sqludf_locator *result; /* locator result */
タイプ udf_locator はヘッダー・ファイル sqludf.h で定義されています。このヘッダー・ファイルについては、UDF インクルード・ファイル: sqludf.h で説明されています。これらのロケーターの使用については、UDF のパラメーターや結果としての LOB ロケーターの使用で説明されています。
UDF を 32 ビット・プラットフォームと 64 ビット・プラットフォームの間で移送できるようにするには、 64 ビット値を含むスクラッチパッドを作成および使用する仕方を変えなければなりません。 1 つまたは複数の 64 ビット値 (64 ビット・ポインターや sqlint64 BIGINT 変数など) を含むスクラッチパッド構造では、明示的な長さ変数を宣言してはなりません。たとえば、以下の例を実行すると、構造宣言の中に明示的な長さ変数が含まれているため、 64 ビット・プラットフォームではデータ位置合わせ例外になる可能性があります。
struct scratch1 { sqlint32 length; char chars[4]; sqlint64 bigint_var; };
上記の例において、32 ビット・プラットフォームと 64 ビット・プラットフォームの間での移送が可能になるようにスクラッチパッド構造を宣言するには、その構造に関連した明示的な長さ変数の宣言を取り除く必要があります。以下の例では、明示的な長さ変数を宣言せずにスクラッチパッド構造を宣言しています。
struct scratch1 { sqlint64 bigint_var; char chars[4]; };
UDF 内で明示的な長さ変数を宣言していないスクラッチパッド構造にアクセスするには、以下のような形式でスクラッチパッドを参照します。
struct scratchpad_data * data = (struct scratchpad_data*)scratch_pointer->data;
ここで、 scratch_pointer は UDF の sqludf_scratchpad ポインターを、 data はスクラッチパッドの内容を表しています。
このインクルード・ファイルには、 UDF を定義する際に役立つ構造、定義、および値が含まれます。このインクルード・ファイルは任意に使用できますが、UDF コードの例で示すサンプル UDF の例ではこのファイルを使用します。 UDF のコンパイル時には、このファイルがあるディレクトリーを参照する必要があります。そのディレクトリーは sqllib/include です。
sqludf.h インクルード・ファイルは自己記述性です。以下にその内容について簡単に要約します。
また、AS LOCATOR 付加を使用して定義される引き数や結果の C 言語タイプも含まれます。
次の項では、UDF の例を示して sqludf.h の包含と使用について説明します。