php pdo & iSeriesAccess ODBC - 使用 OUT 参数调用存储过程不起作用
Posted
技术标签:
【中文标题】php pdo & iSeriesAccess ODBC - 使用 OUT 参数调用存储过程不起作用【英文标题】:php pdo & iSeriesAccess ODBC - Calling Stored Procedures with OUT Parameters Does Not Work 【发布时间】:2016-01-04 23:56:35 【问题描述】:我们在工作中使用一个非常古老的系统来管理业务中最重要的部分......我在这件事上别无选择。
因此,我设法让 php 的 pdo 驱动程序与 iSeriesAccess 数据库驱动程序一起工作,并且就选择和插入而言,它运行良好,但有一些不值得一提的注意事项。
使用此代码,由于我尚未解决的错误,我无法获取输出到 OUT 参数的存储过程以执行。
$proc = $this->link->prepare("CALL QGPL.PROCNAMEHERE(\"*STRANGEPARAMNAMEHERE\",@output,' ')");
$proc->execute();
$proc->closeCursor();
$output = $this->link->query("select @output")->fetch(PDO::FETCH_ASSOC);
var_dump($output);
产生的错误:
Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 0 [IBM][System i Access ODBC Driver][DB2 for i5/OS]SQL0206 - Column or global variable @OUTPUT not found.
我知道我们公司的另一个人用 java 编写成功地在他的代码中调用了这个过程,但是我知道他可能有不同的驱动程序要使用。
这个问题快把我逼疯了,以至于我尝试在 DBeaver 中使用声明的变量手动调用它......这会导致更奇怪的错误。
按照下面的建议使用,我得到了
结果
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 0 [IBM][System i Access ODBC Driver][DB2 for i5/OS]SQL0206 - Column or global variable *RTNORD not found. (SQLPrepare[0] at /build/php5-pO28mL/php5-5.5.9+dfsg/ext/pdo_odbc/odbc_driver.c:206)'
【问题讨论】:
此时我们正在考虑用 C#/mono 或 java 编写帮助程序,因为我们知道它们应该能够与服务器通信,而用于 Linux 的 iAccess 连接器至少拒绝处理对 OUT 生成程序的调用。我们还没有测试过其他程序类型。 我使用 jt400.jar 编写了一个“正常工作”的 java 应用程序,只要我指定它可以使用的库,并设置 Naming=sql。 对于 php,iAccess 似乎不能很好地与 odbc 进行参数化查询,或者它与 pdo 的处理方式不兼容。我计划联系这两个项目的邮件列表并提供一些详细信息,如果我让它在 php 下本地工作,我会更新这个页面。 不管其他很多事情,如果我们需要考虑访问给定的存储过程,则需要包含存储过程接口的定义。要么显示创建存储过程的那部分源代码,要么从 DB2 检索它并显示它。将线条粘贴到问题中。没有它,可能就没有有用的进展。 这是不可能的,因为该软件不是我们自己的,也不是第 3 方,已签约,没有可用的来源。我已经尝试让 db2 向我展示源代码,但这是一个程序,而不是存储过程。如果我更习惯于其他数据库系统,请原谅我的条款。 【参考方案1】:您似乎正试图在代码中使用 mysql session variables,这在 DB2 上不起作用。
我会查看 PDO 的 bindParam,尤其是示例 2 和 3。这样的东西应该可以工作:
$bufsize = 100; // Adjust according to how big the output can be
$proc = $this->link->prepare("CALL QGPL.PROCNAMEHERE('*STRANGEPARAMNAMEHERE', ?,' ')");
$proc->bindParam(1, $output, PDO::PARAM_STR|PDO::PARAM_OUTPUT, $bufsize);
$proc->execute();
$proc->closeCursor();
var_dump($output);
如果你只是调用一个程序,你可能需要创建一个 SQL 过程定义,否则你不能准备语句(因为 SQL 不知道参数被定义为什么)。请参阅 IBM i SQL 参考的 this 部分,例如。
CREATE OR REPLACE PROCEDURE QGPL.PROCNAMEHERE(IN C CHAR(20), OUT D CHAR(100))
LANGUAGE CL
PARAMETER STYLE GENERAL
EXTERNAL NAME 'QGPL/PROCNAMEHERE';
【讨论】:
我知道这在理论上应该可行,但它也行不通。我怀疑这可能是因为,正如我最近了解到的,这不是传统的存储过程,而是某种程序挂钩到我们使用的古老管理系统中。在上面添加评论。 如果我切换到使用单引号封装的字符串进行调用,它返回名称 " 是不允许的...我高度怀疑这是一个字符编码错误,因为这个小 Java 应用程序我写来完美地做到这一点。 哦,是的,双引号用于分隔标识符,因此将解析为名为 *STRANGEPARAMNAMEHERE 的列名或变量。使用单引号会给你一个字符串。 如果您调用的是程序而不是存储过程,那么您将很难让输出参数正常工作。我建议为您可以调用的程序创建一个SQL Procedure 定义:create or replace procedure qgpl.procnamehere(in c char(10), out d char(10)) language CL parameter style general external name 'QGPL/PROCNAMEHERE';
不幸的是,我相信我的第一次尝试也已经尝试过了……我开始认为我正在寻找非标准配置。 DBA 有两种不同的方法指向这个程序,无论我尝试多少次按摩参数,在 php 中都不会很好。以上是关于php pdo & iSeriesAccess ODBC - 使用 OUT 参数调用存储过程不起作用的主要内容,如果未能解决你的问题,请参考以下文章