CREATE PROCEDURE 语句

CREATE FUNCTION 和 CREATE PROCEDURE 语句定义可调用的函数或过程(通常称为例程)。

语法

注:
  1. 如果例程类型为 FUNCTION,则方向指示符(IN、OUT、INOUT)对于每个参数都是可选的。不过,出于记录目的,为所有任意类型的新例程指定方向指示符是很好的编程做法。
  2. 使用 NAMESPACE 或 NAME 子句时,它们的值是 CHARACTER 类型的隐式常量。有关使用 CONSTANT 变量的信息,请参阅 DECLARE 语句
  3. 如果例程类型为 FUNCTION,则无法指定 DATABASE 的 LANGUAGE。

概述

CREATE FUNCTION 和 CREATE PROCEDURE 语句定义可调用的函数或过程(通常称为例程)。

注: 在先前版本的本产品中,CREATE FUNCTION 和 CREATE PROCEDURE 具有不同的用途和功能。但一直以来,它们的变化都不大。函数与过程的唯一不同之处列在了语法图下的注释 1 和 3 中。

例程在创建可复用的代码块时很有用,这些代码块可以独立执行许多次。它们可以实现为一系列 ESQL 语句、一个 Java 方法或数据库存储过程。这种灵活性意味着语法图中的某些子句并非适用于(或允许用于)所有类型的例程。

每个例程都有一个名称,该名称在例程所在的模式中必须是唯一的。这意味着不能重载例程名称;如果代理检测到重载的例程,会抛出异常。

LANGUAGE 子句指定用于编写例程主体的语言。选项为:
DATABASE
作为数据库存储过程调用的过程。
ESQL
作为 ESQL 例程调用的过程。
JAVA
Java 类中作为静态方法调用的过程。
Unspecified
如果未指定 LANGUAGE 子句,除非您指定了 EXTERNAL NAME 子句,这种情况下缺省语言为 DATABASE,否则缺省语言为 ESQL。
以下是使用 LANGUAGE 子句时的局限性。请勿:
  • 将 ESQL 选项与 EXTERNAL NAME 子句一起使用
  • 使用 DATABASE 或 JAVA 选项而不使用 EXTERNAL NAME 子句
  • 将 DATABASE 选项与例程类型 FUNCTION 一起使用

使用 RoutineName 子句可以指定例程的名称,使用 ParameterList 子句可以指定例程的参数。如果 LANGUAGE 子句指定 ESQL,则必须使用一条 ESQL 语句实现该例程。此语句如果是复合语句(BEGIN ... END),就能发挥最大的效用,因为它可以包含所有必要的 ESQL 语句完成其功能。

或者,您也可以指定 LANGUAGE 子句而不是 ESQL,这样就不必为例程提供 ESQL 主体。LANGUAGE 子句允许您使用 EXTERNAL NAME 子句引用实际的例程主体,不管它在代理外部的什么地方。有关使用 EXTERNAL NAME 子句的更多详细信息,请参阅调用存储过程调用 Java 例程

任何 LANGUAGE 类型的例程都可以具有 IN、OUT 和 INOUT 参数。调用者可以使用它们将多个值传递到例程中,并收回多个更新的值。这是除 RETURNS 子句外,例程还可以具有的参数。RETURNS 子句允许例程将值传递回调用者。

用不同语言实现的例程对可以传递或返回的数据类型有它们自己的限制,下面描述了这些限制。返回值的数据类型必须与定义用来从例程返回的值的数据类型相匹配。另外,如果将例程定义为具有返回值,例程的调用者就不能忽略它。关于更多详细信息,请参阅 CALL 语句

例程可以在模块或模式中定义。在模块中定义的例程在当前节点的作用域是本地,这意味着只有属于同一模块(或节点)的代码才能调用它们。但是,在模式作用域中定义的例程可以被任何以下代码调用:
  • 同一模式中的代码。
  • 任何其他模式中的代码(只要满足以下任一条件即可):
    1. 其他模式的 PATH 子句包含被调用例程的路径,或者
    2. 调用的例程是使用标准名称调用的,标准名称即名称加上其模式名称作为前缀,这两者之间用句点隔开。
因此,如果需要在多个节点中调用同一个例程,则在模式中定义它。

对于任何语言或例程类型,例程的调用方法必须与例程的声明方式相匹配。如果例程具有 RETURNS 子句,则使用 FUNCTION 调用语法或带有 INTO 子句的 CALL 语句。反之,如果例程没有 RETURNS 子句,则必须使用不带 INTO 子句的 CALL 语句。

参数方向

传递给例程的参数始终具有与其关联的方向。它可以是下列任何一个方向:
IN
例程无法更改参数的值。允许参数使用 NULL 值,并且可以将该值传递给例程。
OUT
当调用的例程收到 OUT 时,传递给例程的参数始终具有正确数据类型的 NULL 值。无论例程被调用前该参数的值是什么,传递给例程之后都是 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.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

Java 例程

Java 例程作为 Java 方法实现,并且其 LANGUAGE 子句为 JAVA。对于 Java 例程,ExternalRoutineName 必须包含要调用的 Java 方法的类名和方法名。请按如下格式指定 ExternalRoutineName
 >>--"-- className---.---methodName--"--------------><
其中 className 标识包含该方法的类,methodName 标识要调用的方法。如果类是程序包的一部分,类标识部分必须包含完整的程序包前缀;例如“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 空数据类型。参数的数据类型也必须在 ESQL 到 Java 数据类型映射表中。另外,Java 方法的特征符中不能有 exception throws 子句。

Java 方法的特征符必须与 ESQL 例程的方法声明匹配。此外,您还必须遵守以下规则:
  • 确保 Java 方法名(包括类名和所有包限定符)与过程的 EXTERNAL NAME 匹配。
  • 如果 Java 的返回类型为空,请勿在 ESQL 例程的定义中放置 RETURNS 子句。反之,如果 Java 的返回类型不为空,则必须在 ESQL 例程的定义中放置 RETURNS 子句。
  • 确保每个参数的类型和方向按照 ESQL 到 Java 数据类型映射内表中列出的规则与 ESQL 声明匹配。
  • 确保方法的返回类型与 RETURNS 子句的数据类型匹配。
  • 将 EXTERNAL NAME 括在引号中,因为它必须至少包含“class.method”。
  • 如果要调用重载的 Java 方法,必须为每个重载的方法创建一个单独的 ESQL 定义,并赋给每个 ESQL 定义一个唯一的例程名称。

您可以在 Java 方法中使用用户定义的 Java 节点(UDN)API,前提是要遵守Java 例程的局限性中描述的限制。关于使用 UDN API 的更多信息,请参阅编译 Java 用户定义的节点

Java 例程示例 1

该例程包含三个不同方向的参数并返回整数,该整数映射到 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

该例程包含三个不同方向的参数,并且 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 数据类型。每个包装器数组只包含一个元素。
  • 标量对象包装器允许在 Java 方法间传递 NULL 值。
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 方法时不能为 NULL。
  4. 引用参数在传递到 Java 方法时不能有方向 OUT。
  5. 如果 MbElement 作为 INOUT 参数从 Java 传回 ESQL,它必须指向消息树中的一个位置,传递到被调用 Java 方法的 MbElement 也指向此消息树。

    例如,如果对 OutputRoot.XML.Test 的 ESQL 引用作为 INOUT MbElement 传递到 Java 方法,但是调用返回时另一个 MbElement 被传回到 ESQL,那么此元素必须也指向 OutputRoot 树中的某个位置。

  6. 由于 ESQL 例程无法返回引用,因此使用 RETURNS 子句无法从 Java 方法返回 MbElement。但是如果符合上述第 5 点中所述的条件,MbElement 也可以作为 INOUT 方向参数返回。

如果引用所引用的变量数据类型与 Java 程序特征符中相应的数据类型相匹配,则可以在 Java 方法的 CALL 中使用对标量变量的引用。

Java 例程的局限性

以下局限性适用于从 ESQL 调用的 Java 例程:
  • 必须确保 Java 方法是线程安全(可重入)的。
  • 唯一允许的数据库连接是 4 类 JDBC 连接。此外,数据库操作不是代理事务的一部分;这意味着它们不受外部资源协调程序的控制(例如 XA 环境中的情况)。
  • 用户定义的 Java 节点(UDN)API 只应由调用 Java 方法的同一线程使用。

    您可以在自己的方法中衍生线程。但是,衍生的线程不得使用 Java 插件 API,并且您必须将控制权交还给代理。

    请注意,适用于 UDN API 用法的所有局限性也适用于从 ESQL 调用的 Java 方法。

  • 从 ESQL 调用的 Java 方法不得使用 MbNode 类。这意味着它们无法创建 MbNode 类型的对象,或者无法调用现有 MbNode 对象上的任何方法。
  • 如果要在从 ESQL 调用的 Java 方法中执行 MQ 或 JMS 操作,必须按照用户定义的节点(UDN)准则在 UDN 中执行 MQ 和 JMS 操作。

部署 Java 类

您可以在 Java 归档(JAR)文件中部署 Java 类。有两种方法可将 JAR 文件部署到代理中:
  1. 通过将它添加到代理归档(BAR)文件中

    将 JAR 文件添加到 BAR 文件,这是部署到代理的最高效、灵活的方法。

    您可以将 JAR 文件手动或使用工具自动添加到 BAR 文件中。使用工具将 JAR 文件添加到 BAR 文件是最简单的方法。

    如果工具在工作空间中打开的被引用 Java 项目中找到正确的 Java 类,它会自动将该 Java 类编译成 JAR 文件并添加到 BAR 文件中。这与您在 JAR 中部署 Java Compute 节点的过程相同,如用户定义的节点类装入中所述。

    使用工具部署 JAR 文件时,重新部署包含 JAR 文件的 BAR 文件会导致重新部署的流重新装入引用的 Java 类;就象停止并重新启动引用 Java 类的消息流一样。请确保停止并重新启动(或重新部署)所有引用待更新 JAR 文件的流。这样可以避免某些流与旧版本的 JAR 文件一起运行,而其他流与新版本的 JAR 文件一起运行产生的问题。

    请注意,使用工具将只部署 JAR 文件;它不部署单独的 Java 类文件。

  2. 通过将它放在以下的任一位置:
    1. 运行代理的机器上的 <Workpath>/shared-classes/ 文件夹
    2. 运行代理的机器上的 CLASSPATH 环境变量

    此过程必须手动完成;不能使用工具。

    使用这种方法时,重新部署消息流不会导致重新装入引用的 Java 类;停止并重新启动消息流也不会。在这种情况下,重新装入类的唯一方法是停止并重新启动代理自身。

要使代理能够找到 Java 类,请确保该类在上述任一位置中。如果代理找不到指定的类,它会抛出异常。

尽管在部署 JAR 文件时可以进行上述选择,但允许使用工具部署 BAR 文件,这样在重新部署 JAR 文件时最为灵活。

数据库例程

数据库例程是作为数据库存储过程实现的例程。数据库例程具有 LANGUAGE 子句 DATABASE,并且必须具有例程类型 PROCEDURE。

当使用 C 这样的语言编写存储过程时,必须使用 NULL 指示符以确保您的过程能正确处理数据。

尽管存储过程的数据库定义将随数据库而变化,用于调用它们的 ESQL 不会变化。ESQL 中为参数给定的名称不必匹配它们在数据库一边给定的名称。然而,例程的外部名称(包括任何包或容器规范)必须匹配数据库中它的定义名称。

只对数据库例程允许 DYNAMIC RESULT SET 子句。仅在存储过程返回一个或多个结果集时,才需要该子句。向此子句提供的整数参数必须是 0(零)或以上,并指定将返回的结果集的数量。

如果存储过程返回单个标量值,则需要可选的 RETURNS 子句。

EXTERNAL NAME 子句指定名称,数据库通过该名称识别该例程。该名称可以是限定或非限定名称,其中限定符是定义该过程的数据库模式的名称。如果不提供模式名称,则将数据库连接用户名用作该过程所在的模式。如果该模式中不存在所需的过程,您必须提供明确的模式名称,可在例程定义或在运行时对该例程的 CALL 上提供。关于动态选择包含例程的模式的更多信息,请参阅 CALL 语句。使用限定名时,名称必须括在引号中。

标准例程通常采用以下形式:
 EXTERNAL NAME "mySchema.myProc";
但是,如果过程属于 Oracle 包,则该包作为过程名称的一部分处理。因此,您必须以下列形式提供模式名称和包名:
EXTERNAL NAME "mySchema.myPackage.myProc";

这允许在 CALL 语句中动态选择模式名称,但不是选择包名。

如果过程的名称包含 SQL 通配符(百分号 % 和下划线 _ 字符),则代理修改过程名称以紧靠在每个通配符前面包含数据库转义字符。这确保数据库将通配符作为文字字符接收。例如,假定数据库转义字符是反斜杠,则代理修改以下子句,以便将“mySchema.Proc\_”传递给数据库。;
EXTERNAL NAME "mySchema.Proc_";
所有外部过程有以下局限性:
  • 数据库侧无法覆盖存储过程。如果同一数据库模式中存在多个同名过程,则存储过程被视为重载。如果代理检测到过程已超负荷,则会报告异常。
  • 参数不能是 ESQL REFERENCE、ROW、LIST 或 INTERVAL 数据类型。
  • 用户定义的类型不能用作参数或返回值。

数据库例程示例 1

下面是存储过程的简单 ESQL 定义,该存储过程返回一个标量值和 OUT 参数:

CREATE PROCEDURE myProc1 (IN P1 INT, OUT P2 INT)
	LANGUAGE DATABASE
	RETURNS INTEGER
EXTERNAL NAME "myschema.myproc";

使用该 ESQL 来调用 myProc1 例程:

/*using CALL statement invocation syntax*/
CALL myProc1(intVar1, intVar2) INTO intReturnVar3;

/*or using function invocation syntax*/
SET intReturnVar3 = myProc1(intVar1, intVar2);

数据库例程示例 2

以下 ESQL 代码演示了如何定义和调用 DB2 存储过程:

ESQL 定义:
DECLARE inputParm CHARACTER;
DECLARE outputParm CHARACTER;
DECLARE inputOutputParm CHARACTER;

SET inputParm = 'Hello';
SET inputOutputParm = 'World';
CALL swapParms( inputParm, outputParm, inputOutputParm );

CREATE PROCEDURE swapParms (
    IN parm1 CHARACTER,
    OUT parm2  CHARACTER,
    INOUT parm3 CHARACTER
) EXTERNAL NAME dbSwapParms;

要为 DB2 注册该存储过程,将以下脚本复制到某个文件(例如,test1.sql

-- DB2 Example Stored Procedure
DROP PROCEDURE dbSwapParms @                                       
CREATE PROCEDURE dbSwapParms
( IN in_param CHAR(32), 
    OUT out_param CHAR(32),
    INOUT inout_param CHAR(32))
LANGUAGE SQL
             BEGIN
    SET out_param = inout_param;  
        SET inout_param = in_param;
END @
并执行:
db2 -td@ -vf test1.sql
通过运行此代码要求得到下列结果:
  • IN 参数的值不(并且按定义不能)更改。
  • OUT 参数的值成为“World”。
  • INOUT 参数的值更改为“Hello”。

数据库例程示例 3

以下 ESQL 代码演示了如何定义和调用 Oracle 存储过程:

ESQL 定义:
DECLARE inputParm CHARACTER;
DECLARE outputParm CHARACTER;
DECLARE inputOutputParm CHARACTER;

SET inputParm = 'Hello';
SET inputOutputParm = 'World';
CALL swapParms( inputParm, outputParm, inputOutputParm );

CREATE PROCEDURE swapParms (
    IN parm1 CHARACTER,
    OUT parm2  CHARACTER,
    INOUT parm3 CHARACTER
) EXTERNAL NAME dbSwapParms;

要为 Oracle 注册该存储过程,将以下脚本复制到某个文件(例如,test1.sql

CREATE OR REPLACE PROCEDURE dbSwapParms 
( in_param IN VARCHAR2 ,
    out_param OUT VARCHAR2, 
    inout_param IN OUT VARCHAR2 )
AS
             BEGIN
    out_param := inout_param;    
    inout_param := in_param;
END;
/
并执行:
sqlplus <userid>/<password> @test1.sql
通过运行此代码要求得到下列结果:
  • IN 参数的值不(并且按定义不能)更改。
  • OUT 参数的值成为“World”。
  • INOUT 参数的值更改为“Hello”。

数据库例程示例 4

以下 ESQL 代码演示了如何定义和调用 SQL Server 存储过程:

ESQL 定义:
DECLARE inputParm CHARACTER;
DECLARE outputParm CHARACTER;
DECLARE inputOutputParm CHARACTER;

SET inputParm = 'Hello';
SET inputOutputParm = 'World';
CALL swapParms( inputParm, outputParm, inputOutputParm );

CREATE PROCEDURE swapParms (
    IN parm1 CHARACTER,
  INOUT parm2 CHARACTER,
    INOUT parm3 CHARACTER
) EXTERNAL NAME dbSwapParms;

要为 SQL Server 注册该存储过程,将以下脚本复制到某个文件(例如,test1.sql

-- SQLServer Example Stored Procedure
DROP PROCEDURE dbSwapParms
go
CREATE PROCEDURE dbSwapParms
 @in_param CHAR(32),
 @out_param CHAR(32) OUT,
 @inout_param CHAR(32) OUT
AS
  SET NOCOUNT ON
  SET @out_param = @inout_param
  SET @inout_param = @in_param
go
并执行:
isql -U<userid> -P<password> -S<server> -d<datasource> -itest1.sql
注:
  1. SQL Server 将来自存储过程的 OUTPUT 参数视为 INPUT/OUTPUT 参数。

    如果在您的 ESQL 中将这些参数声明为 OUT 参数,则在运行时会遇到类型不匹配错误。要避免该不匹配错误,您必须将 SQL Server OUTPUT 参数声明为 ESQL 中的 INOUT 参数。

  2. 如上一示例所述,您应该通过 SQL 存储过程来使用 SET NOCOUNT ON 选项,原因如下:
    1. 限制从 SQL Server 返回到代理的数据数量。
    2. 使结果设置得以正确返回。
通过运行此代码要求得到下列结果:
  • IN 参数的值不(并且按定义不能)更改。
  • OUT 参数的值成为“World”。
  • INOUT 参数的值更改为“Hello”。

Database 例程示例 5

以下 ESQL 代码演示了如何定义和调用 SYBASE 存储过程:

ESQL 定义:
DECLARE inputParm CHARACTER;
DECLARE outputParm CHARACTER;
DECLARE inputOutputParm CHARACTER;

SET inputParm = 'Hello';
SET inputOutputParm = 'World';
CALL swapParms( inputParm, outputParm, inputOutputParm );

CREATE PROCEDURE swapParms (
    IN parm1 CHARACTER,
  INOUT parm2 CHARACTER,
    INOUT parm3 CHARACTER
) EXTERNAL NAME dbSwapParms;

要为 SYBASE 注册该存储过程,将以下脚本复制到某个文件(例如,test1.sql

-- SYBASE Example Stored Procedure
DROP PROCEDURE dbSwapParms
go
CREATE PROCEDURE dbSwapParms
 @in_param CHAR(32),
 @out_param CHAR(32) OUT,
 @inout_param CHAR(32) OUT
AS
  SET @out_param = @inout_param
  SET @inout_param = @in_param
go
并执行:
isql -U<userid> -P<password> -S<server> -d<datasource> -itest1.sql
注: SYBASE 将来自存储过程的 OUTPUT 参数视为 INPUT/OUTPUT 参数。

如果在您的 ESQL 中将这些参数声明为 OUT 参数,则在运行时会遇到类型不匹配错误。要避免该不匹配错误,您必须将 SYBASE OUTPUT 参数声明为 ESQL 中的 INOUT 参数。

通过运行此代码要求得到下列结果:
  • IN 参数的值不(并且按定义不能)更改。
  • OUT 参数的值成为“World”。
  • INOUT 参数的值更改为“Hello”。

数据库例程示例 6

该示例显示了如何调用返回两个结果集和输出参数的存储过程:

CREATE PROCEDURE myProc1 (IN P1 INT, OUT P2 INT)
  LANGUAGE DATABASE
  DYNAMIC RESULT SETS 2
  EXTERNAL NAME "myschema.myproc";

使用以下 ESQL 来调用 myProc1

/* using a field reference */
CALL myProc1(intVar1, intVar2, Environment.RetVal[], OutputRoot.XML.A[])
/* using a reference variable*/
CALL myProc1(intVar1, intVar2, myReferenceVariable.RetVal[], myRef2.B[])
相关概念
ESQL 概述
相关任务
正在开发 ESQL
调用存储过程
相关参考
语法图:可用类型
ESQL 语句
CALL 语句
ESQL 到 Java 的数据类型映射表
声明 | 商标 | 下载 | 书库 | 支持 | 反馈
Copyright IBM Corporation 1999, 2006 最后一次更新时间:2006/08/14
ak04970_