CREATE FUNCTION 和 CREATE PROCEDURE 语句定义可调用的函数或过程(通常称为例程)。
例程在创建可复用的代码块时很有用,这些代码块可以独立执行许多次。它们可以实现为一系列 ESQL 语句、一个 Java 方法或数据库存储过程。这种灵活性意味着语法图中的某些子句并非适用于(或允许用于)所有类型的例程。
每个例程都有一个名称,该名称在例程所在的模式中必须是唯一的。这意味着不能重载例程名称;如果代理检测到重载的例程,会抛出异常。
使用 RoutineName 子句可以指定例程的名称,使用 ParameterList 子句可以指定例程的参数。如果 LANGUAGE 子句指定 ESQL,则必须使用一条 ESQL 语句实现该例程。此语句如果是复合语句(BEGIN ... END),就能发挥最大的效用,因为它可以包含所有必要的 ESQL 语句完成其功能。
或者,您也可以指定 LANGUAGE 子句而不是 ESQL,这样就不必为例程提供 ESQL 主体。LANGUAGE 子句允许您使用 EXTERNAL NAME 子句引用实际的例程主体,不管它在代理外部的什么地方。有关使用 EXTERNAL NAME 子句的更多详细信息,请参阅调用存储过程和调用 Java 例程。
任何 LANGUAGE 类型的例程都可以具有 IN、OUT 和 INOUT 参数。调用者可以使用它们将多个值传递到例程中,并收回多个更新的值。这是除 RETURNS 子句外,例程还可以具有的参数。RETURNS 子句允许例程将值传递回调用者。
用不同语言实现的例程对可以传递或返回的数据类型有它们自己的限制,下面描述了这些限制。返回值的数据类型必须与定义用来从例程返回的值的数据类型相匹配。另外,如果将例程定义为具有返回值,例程的调用者就不能忽略它。关于更多详细信息,请参阅 CALL 语句。
对于任何语言或例程类型,例程的调用方法必须与例程的声明方式相匹配。如果例程具有 RETURNS 子句,则使用 FUNCTION 调用语法或带有 INTO 子句的 CALL 语句。反之,如果例程没有 RETURNS 子句,则必须使用不带 INTO 子句的 CALL 语句。
如果例程类型为 FUNCTION,则方向指示符(IN、OUT、INOUT)对于每个参数都是可选的。不过,出于记录目的,为所有任意类型的新例程指定方向指示符是很好的编程做法。
声明为 CONSTANT 的 ESQL 变量(或对声明为 CONSTANT 的变量的引用)不能具有 OUT 或 INOUT 方向。
ESQL 例程使用 ESQL 编写,并且其 LANGUAGE 子句为 ESQL。ESQL 例程的主体通常是 BEGIN … END 格式的复合语句,它包含多个语句用来处理传递给例程的参数。
CREATE PROCEDURE swapParms ( IN parm1 CHARACTER, OUT parm2 CHARACTER, INOUT parm3 CHARACTER ) BEGIN SET parm2 = parm3; SET parm3 = parm1; END;
此过程示例显示如何递归使用 ESQL例程。它通过访问指定的起始点处和起始点下面的所有位置来解析树,并报告发现的内容:
SET OutputRoot.MQMD = InputRoot.MQMD; DECLARE answer CHARACTER; SET answer = ''; CALL navigate(InputRoot.XML, answer); SET OutputRoot.XML.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
>>--"-- className---.---methodName--"--------------><其中 className 标识包含该方法的类,methodName 标识要调用的方法。如果类是程序包的一部分,类标识部分必须包含完整的程序包前缀;例如“com.ibm.broker.test.MyClass.myMethod”。
为找到 Java 类,代理会按部署 Java 类中的描述进行搜索。
public static <return-type> <method-name> (< 0 - N parameters>)
其中 <return-type> 必须是 ESQL 到 Java 数据类型映射内表中的 Java IN 数据类型列表(REFERENCE 类型除外,它不能作为返回值),或者 Java 空数据类型。参数的数据类型也必须在 ESQL 到 Java 数据类型映射表中。另外,Java 方法的特征符中不能有 exception throws 子句。
您可以在 Java 方法中使用用户定义的 Java 节点(UDN)API,前提是要遵守Java 例程的局限性中描述的限制。关于使用 UDN API 的更多信息,请参阅编译 Java 用户定义的节点。
该例程包含三个不同方向的参数并返回整数,该整数映射到 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 返回类型为 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 数据类型 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 | 不支持 | 不支持 |
例如,如果对 OutputRoot.XML.Test 的 ESQL 引用作为 INOUT MbElement 传递到 Java 方法,但是调用返回时另一个 MbElement 被传回到 ESQL,那么此元素必须也指向 OutputRoot 树中的某个位置。
如果引用所引用的变量数据类型与 Java 程序特征符中相应的数据类型相匹配,则可以在 Java 方法的 CALL 中使用对标量变量的引用。
您可以在自己的方法中衍生线程。但是,衍生的线程不得使用 Java 插件 API,并且您必须将控制权交还给代理。
请注意,适用于 UDN API 用法的所有局限性也适用于从 ESQL 调用的 Java 方法。
将 JAR 文件添加到 BAR 文件,这是部署到代理的最高效、灵活的方法。
您可以将 JAR 文件手动或使用工具自动添加到 BAR 文件中。使用工具将 JAR 文件添加到 BAR 文件是最简单的方法。
如果工具在工作空间中打开的被引用 Java 项目中找到正确的 Java 类,它会自动将该 Java 类编译成 JAR 文件并添加到 BAR 文件中。这与您在 JAR 中部署 Java Compute 节点的过程相同,如用户定义的节点类装入中所述。
使用工具部署 JAR 文件时,重新部署包含 JAR 文件的 BAR 文件会导致重新部署的流重新装入引用的 Java 类;就象停止并重新启动引用 Java 类的消息流一样。请确保停止并重新启动(或重新部署)所有引用待更新 JAR 文件的流。这样可以避免某些流与旧版本的 JAR 文件一起运行,而其他流与新版本的 JAR 文件一起运行产生的问题。
请注意,使用工具将只部署 JAR 文件;它不部署单独的 Java 类文件。
此过程必须手动完成;不能使用工具。
使用这种方法时,重新部署消息流不会导致重新装入引用的 Java 类;停止并重新启动消息流也不会。在这种情况下,重新装入类的唯一方法是停止并重新启动代理自身。
要使代理能够找到 Java 类,请确保该类在上述任一位置中。如果代理找不到指定的类,它会抛出异常。
尽管在部署 JAR 文件时可以进行上述选择,但允许使用工具部署 BAR 文件,这样在重新部署 JAR 文件时最为灵活。