CALL 语句

CALL 语句调用过程或外部过程。

调用

此语句可以嵌入在应用程序中,也可通过动态 SQL 语句来发出。 它是可动态准备的可执行语句。

使用命令行处理器调用时,有一些其他规则用于指定过程的自变量。

有关更多信息,请参阅使用命令行 SQL 语句和 XQuery 语句

权限

语句授权标识所拥有的特权必须至少包括下列其中一项权限:
  • 对程序的 EXECUTE 特权
  • DATAACCESS 权限

如果存在未授权语句的授权标识执行的匹配过程,那么将返回错误 (SQLSTATE 42501)。

语法

Read syntax diagramSkip visual syntax diagramCALLprocedure-name(,argument)
argument
Read syntax diagramSkip visual syntax diagramparameter-name=>expressionDEFAULTNULL

描述

procedure-name
指定要调用的过程。 它必须是在目录中描述的过程,或者在包含 CALL 语句的复合 SQL (编译型) 语句的作用域中声明的过程。 使用过程解析来选择要调用的特定过程。 (有关更多详细信息,请参阅此语句的 Notes 部分。)
参数
参数名称
将自变量分配到的参数的名称。 当参数按名称分配给参数时,也必须按名称分配后跟的所有参数 (SQLSTATE 4274K)。

指定的自变量必须仅指定一次 (隐式或显式) (SQLSTATE 4274K)。

对未编目过程的调用不支持指定的自变量 (SQLSTATE 4274K)。

expressionDEFAULT 或 NULL
表达式DEFAULT 关键字或 NULL 关键字都是 CALL 的自变量。 CALL 语句的 nth 未命名 自变量对应于该过程的 CREATE PROCEDURE 语句中定义的 n参数。

指定的参数对应于相同的指定参数,而不考虑它们的指定顺序。

如果指定了 DEFAULT 关键字,那么将使用 CREATE PROCEDURE 语句中定义的缺省值 (如果存在); 否则,将使用空值作为缺省值。

如果指定 NULL 关键字,那么会将 null 值作为参数值进行传递。

CALL 的每个自变量必须与过程定义中的相应参数兼容,如下所示:
  • IN 参数
    • 该自变量必须可分配到该参数。
    • 字符串自变量的分配可使用存储分配规则。
  • OUT 参数
    • 自变量必须是单个变量或参数标记 (SQLSTATE 42886)。
    • 该自变量必须可分配到该参数。
    • 字符串自变量的分配使用检索分配规则。
  • INOUT 参数
    • 自变量必须是单个变量或参数标记 (SQLSTATE 42886)。
    • 该自变量必须可分配到该参数。
    • 字符串自变量的分配在调用时使用存储分配规则,在返回时使用检索分配规则。

注意

  • 参数赋值: 执行 CALL 语句时,会将其每个参数的值 (使用存储赋值) 分配给过程的相应参数。 在调用过程时,可以从自变量列表中省略定义为具有缺省值的参数值。

    执行 CALL 语句时,根据主语言的调用约定将控制权传递给过程。 当过程执行完成时,会将过程的每个参数的值 (使用存储赋值) 分配给定义为 OUT 或 INOUT 的 CALL 语句的相应自变量。 如果该过程返回错误,那么未定义 OUT 自变量,并且 INOUT 自变量保持不变。 有关分配规则的详细信息,请参阅 分配和比较

    当 CALL 语句位于 SQL 过程中并且正在调用另一个 SQL 过程时,通过引用来完成 XML 参数的分配。 当通过引用传递 XML 自变量时,将直接从 XML 自变量中使用输入节点树 (如果有) ,从而保留所有属性 (包括文档顺序,原始节点标识和所有父属性)。

  • 过程特征符: 过程由其模式,过程名称和参数数量标识。 这称为过程特征符,在数据库中必须唯一。 模式中可以有多个具有相同名称的过程,前提是每个过程的参数数量不同。
  • SQL 路径: 可以通过引用限定名 (模式和过程名称) 来调用过程,后跟括在括号内的可选参数列表。 还可以在不使用模式名称的情况下调用过程,从而在具有相同数目的参数的不同模式中选择可能的过程。 在这种情况下, SQL 路径用于帮助进行过程解析。 SQL 路径是为了标识具有相同名称和参数数目的过程而搜索的模式列表。 对于静态 CALL 语句,使用 FUNCPATH 绑定选项指定 SQL 路径。 对于动态 CALL 语句, SQL 路径是 CURRENT PATH 专用寄存器的值。
  • 过程解析: 给定过程调用,数据库管理器必须决定要执行哪些具有相同名称的可能过程。
    当从复合 SQL (编译型) 语句中调用过程并且存在以下任一条件时,将使用本地作用域过程解析:
    • 在同一复合 SQL (编译) 语句中声明与所调用过程同名的过程
    • 在复合 SQL (编译型) 语句中声明与所调用过程同名的过程,在该语句中嵌套了调用该过程的复合 SQL (编译型) 语句
    本地作用域过程解析意味着在过程解析期间仅考虑调用该过程的复合 SQL (编译) 语句作用域内的已声明过程,而不考虑是否存在可能的匹配内置过程,模式过程或模块过程。 全局作用域过程解析 用于所有其他情况,并根据调用上下文和过程名称的限定来考虑来自模式和模块的候选者。
    • A 是过程调用中的自变量数。
    • P 是过程特征符中的参数数。
    • N 是不带缺省值的参数的数目。
    根据以下条件选择用于解析过程调用的候选过程:
    • 每个候选过程都具有匹配的名称和适用的参数数。 适用的参数数量满足条件 NAP
    • 每个候选过程都有参数,因此对于 CALL 语句中的每个指定参数,都存在具有与位置 (或未命名) 参数尚未对应的匹配名称的参数。
    • 在 CALL 语句中没有相应自变量 (由位置或名称指定) 的候选过程的每个参数都是使用缺省值定义的。
    • 一组一个或多个模式中的每个候选过程都具有与调用该函数的语句的授权标识相关联的 EXECUTE 特权。
    此外,候选过程集取决于调用过程的环境以及过程名称的限定方式。
    • 如果过程名称未限定,那么将使用以下步骤来完成过程解析:
      1. 如果从复合 SQL (编译型) 语句中调用该过程,并且嵌套作用域中存在具有相同名称的已声明过程,请搜索 CALL 语句所嵌套的复合 SQL (编译型) 语句集以查找候选过程。 如果找不到候选过程,那么将返回错误 (SQLSTATE 42884)。 如果找到单个候选过程,那么解析已完成。 如果有多个候选过程,请确定参数数量最少的候选过程,并消除参数数量较多的候选过程。
      2. 如果从模块对象中调用过程,请在模块中搜索候选过程。 如果在上下文模块中找到一个或多个候选过程,那么这些候选过程将包含在 SQL 路径中的模式中的任何候选过程中 (请参阅下一项)。
      3. 使用 SQL 路径中的模式搜索所有模式过程以查找候选过程。 如果在 SQL 路径的模式中找到一个或多个候选过程,那么这些候选过程将包含在上下文模块中的任何候选过程中 (请参阅前一项)。 如果保留单个候选过程,那么解析已完成。 如果有多个候选过程,请从上下文模块中选择过程 (如果仍是候选) ,否则请选择其模式在 SQL 路径中最早的过程。 如果仍有多个候选过程,请确定参数数目最少的候选过程,并消除参数数目较多的候选过程。

      如果在步骤 3 之后没有剩余候选过程,那么将返回错误 (SQLSTATE 42884)。

    • 如果过程名称是限定的,那么将使用以下步骤来完成过程解析:
      1. 如果从复合 SQL (编译型) 语句中调用该过程,并且存在具有相同名称的声明过程,其中限定符与嵌套 CALL 语句的复合 SQL (编译型) 语句集中的复合 SQL (编译型) 语句的标签相匹配,请使用候选过程的匹配标签搜索该复合 SQL (编译型) 语句。 如果找不到候选过程,那么将返回错误 (SQLSTATE 42884)。 如果找到单个候选过程,那么解析已完成。 如果有多个候选过程,请确定参数数量最少的候选过程,并消除参数数量较多的候选过程。
      2. 如果从模块中调用过程,并且限定符与从中调用过程的模块的名称匹配,请在模块中搜索候选过程。 如果限定符是单个标识,那么在与模块名称匹配时将忽略模块的模式名称。 如果限定符是两部分标识,那么在确定匹配时将其与模式限定模块名称进行比较。 如果存在单个候选过程,那么解析已完成。 如果有多个候选过程,请选择参数数目最少的候选过程。 如果限定符不匹配或没有候选过程,请继续执行下一步。
      3. 请将该限定符视为模式名称,并在该模式中搜索候选过程。 如果存在单个候选过程,那么解析已完成。 如果有多个候选过程,请选择参数数目最少且解析完成的候选过程。 如果模式不存在或没有授权候选过程,并且限定符与第一步中模块的名称匹配,那么返回错误。 否则,请继续执行下一步。
      4. 将限定符视为模块名称,而不考虑对模块的 EXECUTE 特权。
        • 如果模块名称是使用模式名称限定的,那么在此模块中搜索已发布的过程以查找候选过程。
        • 如果模块名称未使用模式名称限定,那么模块的模式是 SQL 路径中具有匹配模块名称的第一个模式。 如果找到,那么在此模块中搜索已发布的过程以查找候选过程。
        • 如果使用 SQL 路径找不到模块,请检查是否存在与过程限定符的名称匹配的模块公用别名。 如果找到,那么在此模块中搜索已发布的过程以查找候选过程。

        如果找不到匹配模块或匹配模块中没有候选过程,那么将返回 "找不到过程" 错误 (SQLSTATE 42884)。 如果有多个候选过程,请选择参数数目最少的候选过程。 如果 CALL 语句的授权标识对其余候选过程的模块具有 EXECUTE 特权,那么解析完成,否则将返回授权错误 (SQLSTATE 42501)。

  • 从 SQL 过程检索 DB2_RETURN_STATUS : 如果 SQL 过程成功发出带有状态值的 RETURN 语句,那么将在 SQLCA 的第一个 SQLERRD 字段中返回此值。 如果在 SQL 过程中发出了 CALL 语句,请使用 GET DIAGNOSTICS 语句来检索 DB2_RETURN_STATUS 值。 如果 SQLSTATE 指示错误,那么该值为 -1。 如果未返回任何错误并且未在过程中指定 RETURN 语句,那么值为 0。
  • 从过程返回结果集: 如果调用程序是使用 CLI , JDBC或 SQLJ 编写的,或者调用者是 SQL 过程,那么可以将结果集直接返回给调用者。 该过程指示要返回结果集,方法是在该结果集上声明游标,在结果集上打开游标,并在退出该过程时使该游标保持打开状态。
    在过程结束时:
    • 对于已保持打开的每个游标,结果集将返回给调用者或 (对于 WITH RETURN TO CLIENT 游标) 直接返回给客户机。
    • 仅传递回未读行。 例如,如果游标的结果集有 500 行,并且在该过程终止时该过程已读取其中的 150 行,那么第 151 行到第 500 行将返回给调用者或应用程序 (视情况而定)。
    如果从 CLI 或 JDBC调用了该过程,并且有多个游标保持打开状态,那么只能按打开游标的顺序处理结果集。
  • 提高性能: 将所有自变量的值从应用程序传递到过程。 为了提高此操作的性能,在执行 CALL 语句之前,应该将对应于 OUT 参数且长度超过几个字节的主变量设置为空值。
  • 嵌套 CALL 语句: 可以从例程以及应用程序调用过程。 从例程调用过程时,会将该调用视为嵌套。
    如果过程返回任何查询结果集,那么将按如下所示返回结果集:
    • RETURN TO CALLER 结果集仅对处于先前嵌套级别的程序可见。
    • 仅当从一组嵌套过程中调用了过程时, RETURN TO CLIENT 结果集才可视。 如果函数或方法出现在调用链中的任何位置,那么结果集不可见。 如果结果集可视,那么仅对发出初始过程调用的客户机应用程序可视。
    请考虑以下示例:
      Client program:
      EXEC SQL CALL PROCA;
    
        PROCA:
        EXEC SQL CALL PROCB;
    
          PROCB:
          EXEC SQL DECLARE B1 CURSOR WITH RETURN TO CLIENT ...;
          EXEC SQL DECLARE B2 CURSOR WITH RETURN TO CALLER ...;
          EXEC SQL DECLARE B3 CURSOR FOR SELECT UDFA FROM T1;
    
            UDFA:
            EXEC SQL CALL PROCC;
    
              PROCC:
              EXEC SQL DECLARE C1 CURSOR WITH RETURN TO CLIENT ...;
              EXEC SQL DECLARE C2 CURSOR WITH RETURN TO CALLER ...;
    从过程 PROCB:
    • 游标 B1 在客户机应用程序中可视,但在过程 PROCA 中不可见。
    • 游标 B2 在 PROCA 中可视,但对客户机不可见。
    从过程 PROCC:
    • 游标 C1 对 UDFA 和客户机应用程序都不可见。 (因为 UDFA 出现在客户机与 PROCC 之间的调用链中,所以结果集不会返回给客户机。)
    • 游标 C2 在 UDFA 中可视,但对于任何更高的过程都不可见。
  • 在触发器,复合语句,函数或方法中嵌套过程: 在触发器,复合语句,函数或方法中调用过程时:
    • 该过程不得发出 COMMIT 或 ROLLBACK 语句。
    • 无法访问从过程返回的结果集。
    • 如果该过程定义为 READS SQL DATA 或 MODIFIED SQL DATA ,那么该过程中的任何语句都不能访问正在由调用该过程的语句修改的表 (SQLSTATE 57053)。 如果该过程定义为 MODIFY SQL DATA ,那么该过程中的任何语句都不能修改正在由调用该过程的语句读取或修改的表 (SQLSTATE 57053)。
      在函数或方法中调用过程时:
      • 该过程与调用函数或方法具有相同的表访问限制。
      • 在调用函数或方法之前定义的保存点对过程不可见,并且在过程中定义的保存点在函数或方法之外不可见。
      • 无法从客户机访问从过程返回的 RETURN TO CLIENT 结果集。
  • 来自 Db2® for IBM® iDb2 for z/OS®: 来自 Db2 for IBM iDb2 for z/OS 的 CALL 语句的编译隐式行为,就像指定了 CALL_RESOLUTION DEFERRED 一样。 使用 CALL_RESOLUTION DEFERRED 编译 CALL 语句时,必须通过主变量提供所有自变量,并且不允许使用表达式。
  • 语法替代方法: 存在较旧形式的 CALL 语句,可以通过使用 CALL_RESOLUTION DEFERRED 选项预编译应用程序来将其嵌入到应用程序中。 此选项不可用于 SQL 过程 和联合过程

示例

  • 示例 1: 使用以下语句在数据库中定义 Java™ 过程:
       CREATE PROCEDURE PARTS_ON_HAND (IN PARTNUM INTEGER,
                                       OUT COST DECIMAL(7,2),
                                       OUT QUANTITY INTEGER)
                       EXTERNAL NAME 'parts!onhand'
                       LANGUAGE JAVA
                       PARAMETER STYLE DB2GENERAL;
    Java 应用程序使用以下代码片段来调用此过程:
       ...
       CallableStatement stpCall;
    
       String sql = "CALL PARTS_ON_HAND (?, ?, ?)";
    
       stpCall = con.prepareCall(sql); /*con is the connection */
    
       stpCall.setInt(1, hvPartnum);
       stpCall.setBigDecimal(2, hvCost);
       stpCall.setInt(3, hvQuantity);
    
       stpCall.registerOutParameter(2, Types.DECIMAL, 2);
       stpCall.registerOutParameter(3, Types.INTEGER);
    
       stpCall.execute();
    
       hvCost = stpCall.getBigDecimal(2);
       hvQuantity = stpCall.getInt(3);
       ...

    此应用程序代码片段将调用类 parts中的 Java 方法 onhand ,因为在 CALL 语句上指定的过程名称是在数据库中找到的,并且具有外部名 parts!onhand

  • 示例 2: 在四个不同的模式中,有六个 FOO 过程按如下所示注册 (请注意,并非所有必需的关键字都出现):
       CREATE PROCEDURE AUGUSTUS.FOO (INT) SPECIFIC FOO_1 ...
       CREATE PROCEDURE AUGUSTUS.FOO (DOUBLE, DECIMAL(15, 3)) SPECIFIC FOO_2 ...
       CREATE PROCEDURE JULIUS.FOO (INT) SPECIFIC FOO_3 ...
       CREATE PROCEDURE JULIUS.FOO (INT, INT, INT) SPECIFIC FOO_4 ...
       CREATE PROCEDURE CAESAR.FOO (INT, INT) SPECIFIC FOO_5 ...
       CREATE PROCEDURE NERO.FOO (INT,INT) SPECIFIC FOO_6 ...
    过程引用如下 (其中 I1 和 I2 是 INTEGER 值):
       CALL FOO(I1, I2)
    假定执行此引用的应用程序已建立 SQL 路径,如下所示:
       "JULIUS", "AUGUSTUS", "CAESAR"

    通过算法进行跟踪 ...

    将除去具有特定名称 FOO_6 的过程作为候选过程,因为 SQL 路径中不包含模式 "NERO"。 FOO_1, FOO_3和 FOO_4 将作为候选项消除,因为它们具有错误数量的参数。 将按 SQL 路径确定的顺序考虑其余候选项。 请注意,将忽略自变量和参数的类型。 FOO_5 的参数与 CALL 中的参数完全匹配,但是选择了 FOO_2 ,因为 "AUGUSTUS" 出现在 SQL 路径中的 "CAESAR" 之前。

  • 示例 3: 假定存在以下过程。
    	 CREATE PROCEDURE update_order(
                           IN IN_POID BIGINT, 
                           IN IN_CUSTID BIGINT DEFAULT GLOBAL_CUST_ID,
                           IN NEW_STATUS VARCHAR(10) DEFAULT NULL,
                           IN NEW_ORDERDATE DATE DEFAULT NULL,
                           IN NEW_COMMENTS VARCHAR(1000)DEFAULT NULL)...
    
    还假定全局变量 GLOBAL_CUST_ID 设置为值 1002。 调用该过程以将客户 1002 的订单 5000 的状态更改为 "已发货"。 通过允许其余自变量缺省为空值,使订单数据的其余部分保持原样。
       CALL update_order (5000, NEW_STATUS => 'Shipped')
    
    标识为 1001 的客户已致电并指示他们已收到采购订单 5002 的装运并已满足。 更新他们的订单。
       CALL update_order (5002,
    		     IN_CUSTID => 1001,
    		     NEW_STATUS => 'Received', 
    		     NEW_COMMENTS => 'Customer satisfied with the order.')
    
  • 示例 4: 以下示例说明了给定两个名为 p1的过程的过程解析:
       CREATE PROCEDURE p1(i1 INT)...
       CREATE PROCEDURE p1(i1 INT DEFAULT 0, i2 INT DEFAULT 0)...
       CALL p1(i2=>1)
    在候选人选择过程中,将考虑参数名称。 因此,只有 p1 的第二个版本将被视为候选者。 此外,由于此版本的 p1 中的 i1 是使用缺省值定义的,因此可以成功调用此命令。 在调用 p1 时指定 i2 是有效的。
  • 示例 5: 以下示例是过程解析的另一个说明,给定两个名为 p1的过程:
       CREATE PROCEDURE p1(i1 INT, i2 INT DEFAULT 0)...
       CREATE PROCEDURE p1(i1 INT DEFAULT 0, i2 INT DEFAULT 0, i3 INT DEFAULT 0)...
       CALL p1(i2=>1)
    在 CALL 语句中没有相应参数 (由位置或名称指定) 的过程参数的条件之一是使用缺省值定义参数。 因此, p1 的第一个版本不会被视为候选者。