CREATE FUNCTION ステートメント

CREATE FUNCTION ステートメントは、呼び出し可能な関数またはプロシージャーを定義します。

CREATE PROCEDURE ステートメントを使用して、呼び出し可能な関数またはプロシージャー (ルーチンともいう) を定義することもできます。

構文

注:
  1. ルーチンのタイプが FUNCTION の場合、方向標識 (IN、OUT、または INOUT) はパラメーターごとにオプションです。 しかし、文書化の目的上、新しいルーチンすべてに方向標識を指定することは適切なプログラミング手法です。方向を指定しない場合、デフォルト値 IN が使用されます。
  2. NAMESPACE または NAME 文節を使用すると、その値は暗黙的にタイプ CHARACTER の CONSTANT になります。 CONSTANT 変数の使用に関する情報については、DECLARE ステートメントを参照してください。
  3. ルーチンのタイプが FUNCTION の場合には、DATABASEの LANGUAGE を指定することはできません。

概説

CREATE FUNCTION および CREATE PROCEDURE ステートメントは、呼び出し可能な関数またはプロシージャー (ルーチンともいう) を定義します。

以前のバージョンのこの製品では、CREATE FUNCTION と CREATE PROCEDURE の使用法と機能は互いに異なっていました。その後の機能拡張により、 前述の注 1 および 3 にリストされている差異が生じました。

ルーチンは、個別に複数回実行できる再使用可能なコード・ブロックを作成するのに便利です。 一連の ESQL ステートメント、Java™ メソッド、またはデータベース・ストアード・プロシージャーとしてルーチンをインプリメントできます。 このような柔軟性があるので、構文図の文節の中には、ルーチンのタイプによっては適用されない (または許可されない) ものがあります。

個々のルーチンには名前があり、この名前はそのルーチンが属するスキーマ内で固有でなければなりません。したがって、ルーチン名は多重定義できません。ルーチン名が多重定義であることをブローカーが検出すると、例外が生じます。

LANGUAGE 文節は、ルーチンの本体を作成するときの言語を指定します。オプションは、以下のとおりです。
DATABASE
プロシージャーはデータベース・ストアード・プロシージャーとして呼び出されます。
ESQL
プロシージャーは ESQL ルーチンとして呼び出されます。
JAVA
プロシージャーは Java クラスの静的メソッドとして呼び出されます。
指定されていない
LANGUAGE 文節を指定しない場合、EXTERNAL NAME 文節を指定していなければ、 デフォルトの言語は ESQL になります (EXTERNAL NAME 文節を指定したときは、デフォルトの言語は DATABASE になります)。
LANGUAGE 文節の使用については制限があります。 以下のオプションは使用できません。
  • EXTERNAL NAME 文節を使用した ESQL オプション。
  • EXTERNAL NAME 文節を使用しない DATABASE または JAVA オプション。
  • ルーチン・タイプ FUNCTION を使用した DATABASE オプション。

RoutineName 文節を使用してルーチンの名前を指定し、ParameterList 文節を使用してルーチンのパラメーターを指定してください。 LANGUAGE 文節で ESQL を指定している場合、単一の ESQL ステートメントを使用してルーチンをインプリメントします。 このステートメントは複合ステートメント (BEGIN ... END) の場合に最も便利です。なぜなら、後で必要な数だけ ESQL ステートメントを組み込んで、その機能を実現できるからです。

ルーチンに ESQL 本体を提供する代わりに、ESQL 以外の LANGUAGE 文節を指定することもできます。この場合、ルーチンの実際の本体がブローカーの外部のどの場所にあっても、EXTERNAL NAME 文節を使用してその本体に対する参照を提供できます。EXTERNAL NAME 文節の使用法について詳しくは、ストアード・プロシージャーの呼び出し、および Java ルーチンの呼び出しを参照してください。

LANGUAGE タイプのルーチンに IN、OUT、および INOUT パラメーターを指定できます。呼び出し元がルーチンに複数の値を渡したり、複数の更新された値を戻して受け取ったりできます。戻されるこれらのパラメーターは、ルーチンに関する定義済みの RETURNS 文節に付加されます。RETURNS 文節は、ルーチンが呼び出し元に戻す値を定義します。

さまざまな言語でインプリメントされるルーチンには、データ・タイプを渡したり戻したりする上での独自の制約事項があり、これらの制限についてはこのセクションで後述されています。 戻り値のデータ・タイプは、ルーチンから戻されるように定義された値のデータ・タイプと一致していなければなりません。 また、ルーチンが戻り値を持つように定義されている場合は、ルーチンの呼び出し元はその値を無視できません。詳細については、CALL ステートメントを参照してください。

ルーチンは、モジュールまたはスキーマの中に定義できます。モジュールで定義されたルーチンは現行ノードでのみ有効な、ローカルなものです。つまり、この同じモジュール (またはノード) に属するコードのみルーチンを起動できます。 しかし、スキーマ内で定義されたルーチンは、 以下のいずれかのオプションを使用することにより起動できます。
  • 同じスキーマ内のコード。
  • 以下のいずれかの条件が該当する場合、他のスキーマ内のコード。
    • 他のスキーマの PATH 文節に、呼び出し先のルーチンへのパスが含まれる。
    • 完全修飾名 (スキーマ名を接頭部として、ピリオドで区切られた名前) を使用して、呼び出し先ルーチンが起動される。
このように、同じルーチンを複数のノードで起動する必要がある場合は、それをスキーマに定義します。

言語またはルーチン・タイプの場合、ルーチンを起動する方式は、ルーチンを宣言する方法と一致していなければなりません。ルーチンに RETURNS 文節がある場合は、FUNCTION 起動構文か、INTO 文節を指定した CALL ステートメントを使用してください。逆に、ルーチンに RETURNS 文節がない場合は、INTO 文節を指定せずに CALL ステートメントを使用しなければなりません。

パラメーターの方向

ルーチンに渡されるパラメーターには、方向が常に関連付けられます。この方向は以下のいずれかのタイプになります。
IN
ルーチンによってこのパラメーターの値を変更できません。このパラメーターには NULL 値を使用でき、ルーチンに渡せます。
OUT
呼び出し先ルーチンで受け取られた場合、そのルーチンに渡されたこのパラメーターには常に正しいデータ・タイプの NULL 値があります。 この値は、ルーチンが呼び出される前の値に関係なく設定されます。ルーチンで、このパラメーターの値を変更できます。
INOUT
INOUT とは IN パラメーターと OUT パラメーターの両方のことです。このパラメーターは値をルーチンに渡し、渡された値はルーチンで変更できます。 このパラメーターには NULL 値を使用でき、ルーチンとの間で受け渡しできます。

ルーチンのタイプが FUNCTION の場合、方向標識 (IN、OUT、INOUT) はパラメーターごとにオプションです。しかし、文書化の目的上、タイプにかかわらず新しいルーチンすべてに方向標識を指定することは適切なプログラミング手法です。

CONSTANT と宣言される ESQL 変数 (または CONSTANT と宣言される変数の参照) は、方向として OUT または INOUT を持つことはできません。

ESQL ルーチン

ESQL ルーチンは ESQL で書かれていて、LANGUAGE 文節として ESQL があります。ESQL ルーチンの本体は、通常は BEGIN … END 形式の複合ステートメントで、ルーチンに渡されるパラメーターの処理用のステートメントが複数含まれています。

ESQL の例 1

次の例は、データベース・ルーチンの例 1 と同じプロシージャーですが、ストアード・プロシージャーではなく ESQL ルーチンとしてインプリメントされます。 このルーチンの CALL 構文と結果は、Java ルーチンに関する制約事項 と同じです。
CREATE PROCEDURE swapParms (
  IN parm1 CHARACTER,
  OUT parm2  CHARACTER,
  INOUT parm3 CHARACTER )
BEGIN 
   SET parm2 = parm3;
   SET parm3 = parm1;
 END;  

ESQL の例 2

この例のプロシージャーでは、ESQL ルーチンの再帰的使用が示されています。この例は、ツリーを解析し、指定された開始点とそれより下のすべての場所を訪問し、それが見つけたものを報告します。

SET OutputRoot.MQMD = InputRoot.MQMD;

  DECLARE answer CHARACTER;
  SET     answer = '';

  CALL navigate(InputRoot.XMLNS, answer);
  SET OutputRoot.XMLNS.Data.FieldNames = answer;


  CREATE PROCEDURE navigate (IN root REFERENCE, INOUT answer CHARACTER)
  BEGIN 
    SET answer = answer || 'Reached Field... Type:' || CAST(FIELDTYPE(root) AS CHAR)||
': Name:' || FIELDNAME(root) || ': Value :' || root || ': ';

    DECLARE cursor REFERENCE TO root;
    MOVE cursor FIRSTCHILD;
    IF LASTMOVE(cursor) THEN
      SET answer = answer || 'Field has children... drilling down ';
    ELSE
      SET answer = answer || 'Listing siblings... ';
    END IF;

    WHILE LASTMOVE(cursor) DO
      CALL navigate(cursor, answer);
      MOVE cursor NEXTSIBLING;
    END WHILE;

    SET answer = answer || 'Finished siblings... Popping up ';
  END;

次の入力メッセージを与えた場合、

<Person>
  <Name>John Smith</Name>
  <Salary period='monthly' taxable='yes'>-1200</Salary>
</Person>

プロシージャーは次の出力を生成します。この出力は手操作でフォーマット設定されています。

  Reached Field... Type:16777232: Name:XML: Value :: Field has children...
drilling down
Reached Field... Type:16777216: Name:Person: Value :: Field has children...
drilling down
Reached Field... Type:16777216: Name:Name:
  Value :John Smith: Field has children... drilling down
  Reached Field... Type:33554432: Name::
  Value :John Smith: Listing siblings... Finished siblings... Popping up
  Finished siblings... Popping up
  Reached Field... Type:16777216: Name:Salary:
  Value :-1200: Field has children... drilling down
  Reached Field... Type:50331648: Name:period:
  Value :monthly: Listing siblings... Finished siblings... Popping up
  Reached Field... Type:50331648: Name:taxable:
  Value :yes: Listing siblings... Finished siblings... Popping up
  Reached Field... Type:33554432: Name::
  Value :-1200: Listing siblings... Finished siblings... Popping up
  Finished siblings... Popping up
  Finished siblings... Popping up
  Finished siblings... Popping up

Java ルーチン

Java ルーチンは、Java メソッドとしてインプリメントされ、LANGUAGE 文節として JAVA があります。Java ルーチンの場合、呼び出される Java メソッドのクラス名とメソッド名が ExternalRoutineName に含まれていなければなりません。以下のように ExternalRoutineName を指定してください。
>>--"-- className---.---methodName--"--------------><
className はメソッドを含むクラスを識別し、methodName は起動するメソッドを識別します。 クラスがパッケージの一部である場合、クラス ID 部分には、完全なパッケージ接頭部を含める必要があります。例えば、"com.ibm.broker.test.MyClass.myMethod" のようにします。

Java クラスを検出するために、ブローカーは、Java クラスのデプロイで説明されている検索方式を使用します。

起動する Java メソッドには、次の基本的なシグニチャーが必要です。
public static <return-type> <method-name> (< 0 - N parameters>)

<return-type> は、ESQL から Java データ・タイプへのマッピングの表にある Java IN データ・タイプのリストに含まれるもの (ただし戻り値として許可されていない REFERENCE タイプを除く)、または Java void データ・タイプでなければなりません。また、パラメーター・データ・タイプは、ESQL から Java データ・タイプへのマッピングの表に含まれるものでなければなりません。さらに、Java メソッドのシグニチャーとして exception throws 文節は使用できません。

Java メソッドのシグニチャーは、メソッドの ESQL ルーチンの宣言と一致している必要があります。以下の規則を守る必要もあります。
  • クラス名やパッケージ修飾子を含め、Java メソッド名がプロシージャーの EXTERNAL NAME と一致するようにしてください。
  • Java 戻りタイプが void であれば、ESQL ルーチンの定義に RETURNS 文節を入れないでください。逆に、Java 戻りタイプが void でない場合は、ESQL ルーチンの定義に RETURNS 文節を入れる必要があります。
  • 各パラメーターのタイプおよび方向が、ESQL から Java データ・タイプへのマッピングの表にリストされた規則に従い、ESQL 宣言と一致するようにしてください。
  • メソッドの戻りタイプが、RETURNS 文節のデータ・タイプと一致するようにしてください。
  • EXTERNAL NAME に少なくとも "class.method" を組み込まなければならないので、EXTERNAL NAME を引用符で囲んでください。
  • 多重定義の Java メソッドを起動する場合、多重定義メソッドごとに別々の ESQL 定義を作成し、個々の ESQL 定義に固有のルーチン名を付ける必要があります。

Java メソッド内で Java ユーザー定義ノード API を使用できますが、Java ルーチンに関する制約事項に文書化された制限を遵守した場合に限られます。Java API の使用の詳細については、Java ユーザー定義ノードのコンパイルを参照してください。

Java ルーチンの例 1

このルーチンには方向の違う 3 つのパラメーターが含まれており、Java 戻りタイプ java.lang.Long にマップする整数を戻します。

CREATE FUNCTION  myProc1( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
 RETURNS INTEGER
 LANGUAGE JAVA
 EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod1";

次の ESQL を使用して、myProc1 を起動できます。

CALL myProc1( intVar1, intVar2, intVar3) INTO intReturnVar3;
-- or
SET intReturnVar3 = myProc1( intVar1, intVar2, intVar3);

Java ルーチンの例 2

このルーチンには方向の違う 3 つのパラメーターが含まれており、Java 戻りタイプ void があります。

CREATE PROCEDURE myProc2( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
 LANGUAGE JAVA
 EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod2";

次の ESQL を使用して、myProc2 を起動する必要があります。

CALL myProc2(intVar1, intVar2, intVar3);

次の Java クラスでは、前述の Java の例ごとのメソッドが用意されています。

package com.ibm.broker.test;

class MyClass {
public static Long myMethod1( Long P1, Long[] P2 Long[] P3) { ... }
public static void myMethod2( Long P2, Long[] P2 Long[] P3) { ... }

 /* When either of these methods is called:
    P1 may or may not be NULL (depending on the value of intVar1).
    P2[0] is always NULL (whatever the value of intVar2).
    P3[0] may or may not be NULL (depending on the value of intVar3).
    This is the same as with LANGUAGE ESQL routines.
    When these methods return:
         intVar1 is unchanged
         intVar2 may still be NULL or may have been changed
         intVar3 may contain the same value or may have been changed.
     This is the same as with LANGUAGE ESQL routines.
     
    When myMethod1 returns: intReturnVar3 is either  NULL (if the
    method returns NULL) or it contains the value returned by the 
    method.
 */
}

ESQL から Java データ・タイプへのマッピング

以下の表は、ESQL から Java へのマッピングを要約しています。
注:
  • Java スカラー・ラッパーだけが Java に渡されます。
  • ESQL スカラー型は、プロシージャー・パラメーターの向きに応じて、オブジェクト・ラッパーまたはオブジェクト・ラッパー配列として、Java データ・タイプにマップされます。 個々のラッパー配列には厳密に 1 つのエレメントが含まれます。
  • スカラー・オブジェクト・ラッパーは、ヌル値を Java メソッドとやり取りできるようにするために使用されます。
ESQL データ・タイプ 1 Java IN データ・タイプ Java INOUT および OUT データ・タイプ
INTEGER、INT java.lang.Long java.lang.Long []
FLOAT java.lang.Double java.lang.Double[]
DECIMAL java.math.BigDecimal java.math.BigDecimal[]
CHARACTER、CHAR java.lang.String java.lang.String[]
BLOB byte[] byte[][]
BIT java.util.BitSet java.util.BitSet[]
DATE com.ibm.broker.plugin.MbDate com.ibm.broker.plugin.MbDate[]
TIME 2 com.ibm.broker.plugin.MbTime com.ibm.broker.plugin.MbTime[]
GMTTIME 2 com.ibm.broker.plugin.MbTime com.ibm.broker.plugin.MbTime[]
TIMESTAMP 2 com.ibm.broker.plugin.MbTimestamp com.ibm.broker.plugin.MbTimestamp[]
GMTTIMESTAMP 2 com.ibm.broker.plugin.MbTimestamp com.ibm.broker.plugin.MbTimestamp[]
INTERVAL サポートされていない サポートされていない
BOOLEAN java.lang.Boolean java.lang.Boolean[]
REFERENCE (メッセージ・ツリーへの) 3 4 5 6 com.ibm.broker.plugin.MbElement com.ibm.broker.plugin.MbElement[] (INOUT についてはサポートするが、OUT についてはサポートしない)
ROW サポートされていない サポートされていない
LIST サポートされていない サポートされていない
  1. CONSTANT と宣言される変数 (または CONSTANT と宣言される変数の参照) は、向き INOUT または OUT を持つことはできません。
  2. Java 変数のタイム・ゾーン・セットは重要ではありません。出力 ESQL の必須タイム・ゾーンを取得します。
  3. この参照パラメーターは、Java メソッドに渡された場合はヌルにできません。
  4. 参照は、Java メソッドに渡されるときは向きを OUT にすることはできません。
  5. MbElement が Java から ESQL に INOUT パラメーターとして戻される場合、呼び出された Java メソッドに渡された MbElement が指していたのと同じメッセージ・ツリーの場所を指していなければなりません。

    例えば、OutputRoot.XML.Test に対する ESQL 参照が、Java メソッドに INOUT MbElement として渡されたが、呼び出しが戻されるときに別の MbElement が ESQL に戻される場合、その別のエレメントも OutputRoot ツリーのいずれかの場所を指していなければなりません。

  6. ESQL ルーチンは参照を戻すことができないので、MbElement は RETURNS 文節のある Java メソッドから戻ることはできません。 ただし、ポイント 5 で説明した条件に従って、MbElement は向きが INOUT のパラメーターとして戻すことができます。

スカラー変数への REFERENCE を、Java メソッドの CALL の中で使用できます。ただし、参照先の変数のデータ・タイプが、Java プログラムのシグニチャー内の対応するデータ・タイプと一致している場合に限ります。

Java ルーチンに関する制約事項

以下の制約事項が、ESQL から呼び出された Java ルーチンに適用されます。
  • Java メソッドはスレッド・セーフ (再入可能) でなければなりません。
  • データベース接続は JDBC タイプ 2 またはタイプ 4 でなければなりません。 さらに、データベース操作はブローカー・トランザクションの一部ではありません。したがって、データベース操作を外部リソース・コーディネーターによって制御することはできません (XA 環境ではこれが可能)。
  • Java ユーザー定義ノード API の使用は、Java メソッドを呼び出したのと同じスレッドだけに限る必要があります。

    メソッド内にスレッドを作成することができます。 ただし、作成したスレッドは Java API を使用してはならず、制御をブローカーに戻す必要があります。

    Java API の使用法に適用されるすべての制限は、ESQL から呼び出された Java メソッドにも適用されます。

  • ESQL から呼び出された Java メソッドは MbNode クラスを使用してはいけません。 したがって、MbNode タイプのオブジェクトを作成できず、また既存の MbNode オブジェクトのメソッドを呼び出すこともできません。
  • ESQL から呼び出された Java メソッドの内部で WebSphere® MQ または JMS 処理を実行するには、ユーザー定義ノード内で WebSphere MQ および JMS 処理を実行するためのガイドラインに従う必要があります。 変更の始まりユーザー定義の入力ノードの計画を参照してください。変更の終わり

Java クラスのデプロイ

以下の 2 つの方式のいずれかを使用して、Java クラスを Java アーカイブ (JAR) ファイル中のブローカーにデプロイすることができます。
  1. JAR ファイルをブローカー・アーカイブ (BAR) ファイルに追加する

    ブローカーにデプロイするための最も効率的かつ柔軟な方式は、JAR ファイルを BAR ファイルに追加することです。 これは、ワークベンチを使用して、手動または自動で実行できます。

    ワークスペース内に開いている、参照される Java プロジェクト内の適切な Java クラスをワークベンチが検出すると、それは自動的に Java クラスを JAR ファイル内にコンパイルして、それを BAR ファイルに追加します。 これは、ユーザー定義ノードのクラス・ロードで説明されている、JAR 内に JavaCompute ノードをデプロイするときに従う手順と同じです。

    ワークベンチから JAR ファイルをデプロイするとき、再デプロイされたフローによって、BAR ファイルに含まれる JAR ファイルが再ロードされます。

    Java クラスを参照するメッセージ・フローを停止して再始動した場合も、ファイルが再ロードされます。更新対象の JAR ファイルを参照するすべてのフローを、必ず停止および再始動 (または再デプロイ) してください。このアクションにより、一部のフローが古いバージョンの JAR ファイルを使って実行され、他のフローが新しいバージョンを使用するという問題を防ぐことができます。

    ワークベンチは JAR ファイルのみをデプロイし、スタンドアロン Java クラス・ファイルはデプロイしません。

  2. 以下のいずれかの場所に JAR ファイルを格納する
    1. ブローカーを実行しているマシンの workpath/shared-classes/ フォルダー
    2. ブローカーを実行しているコンピューターの CLASSPATH 環境変数

    このアクションはワークベンチを使用して実行できないため、手動で行う必要があります。

    この方法では、メッセージ・フローを再デプロイしたり、メッセージ・フローを停止/再始動しても、参照される Java クラスは再ロードされません。この場合、クラスを再ロードする唯一の方法は、ブローカー自体を停止および再始動することです。

ブローカーが Java クラスを検出できるようにするには、必ず上記のいずれかの場所に格納してください。ブローカーが指定されたクラスを検出できない場合は、例外を生成します。

JAR ファイルをデプロイするときには上記のような複数の選択肢がありますが、ワークベンチを使って BAR ファイルをデプロイすることにより、JAR ファイルを再デプロイするときに最大の柔軟性が得られます。

データベース・ルーチン

CREATE FUNCTION はデータベース・ルーチンをサポートしません。データベース・ルーチンを定義するには CREATE PROCEDURE を使用してください。

関連概念
ESQL の概要
関連タスク
ESQL の開発
ストアード・プロシージャーの呼び出し
Java ユーザー定義ノードのコンパイル
ブローカー・アーカイブへのファイルの追加
関連資料
構文図: 使用可能なタイプ
ESQL のステートメント
CALL ステートメント
CREATE PROCEDURE ステートメント
ESQL から Java へのデータ・タイプ・マッピングの表
関連情報
Java ユーザー定義拡張 API
特記事項 | 商標 | ダウンロード | ライブラリー | サポート | フィードバック

Copyright IBM Corporation 1999, 2009Copyright IBM Corporation 1999, 2009.
最終更新 : 2009-02-20 12:44:01

ak04960_