segfault with unixODBC (DB2) + PHP + CentOS


segfault with unixODBC (DB2) + PHP + CentOS

经过2天的战斗,我尝试在这里寻求帮助。我正在使用 unixODBC (2.2.11) 在 CentOS 5.4 服务器上使用 DB2 (iSeries) 和 PHP (5.3)。我想自从 PHP 从 5.1 升级到 5.3 以来,我让 PHP 在某些查询上出现段错误。经过一些调查,我发现问题出现在一些具有长字符字段的查询中,例如此表:

TABLE (
    CONTRACTID  NUMERIC,
    SOMETEXT    CHAR(583)
)

这段简单的代码引发了段错误:

try {
    $conn = new PDO("odbc:".$dsn, $username, $password, array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
    );
}
catch (Exception $e) {
    echo $e->getMessage();
}
$sql = 'SELECT * FROM LIB.TABLE ';
$stmt = $conn->prepare($sql);
$vals = $stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

unixODBC 和/或 PHP>= 5.1 是否有任何列长度限制或错误?这个Web应用程序工作得很好,然后我遇到了这个问题。

顺便说一句,我用一台更新的 64 位 CentOS 6.2 机器和 unixODBC 2.2.14 和 PHP 5.3 进行了测试,问题是一样的。

任何帮助非常感谢,

谢谢

法比安

更新:使用 PHP odbc 函数,它可以工作:

$conn = odbc_connect($dsn, $username, $password);
$res = odbc_exec($conn, $sql);
$rows = odbc_fetch_array($res);

所以问题更多地与PDO有关,知道吗?

在这里遇到了同样的问题。发现 64 位 php-odbc 模块在返回具有 NULL 值的字段时导致 seg 错误。解决方法是合并可能存在 NULL 值的每个字段。这不是一个好的解决方案。我正在查看php-odbc.c代码,但我不能保证修复。

解决方法:从中选择 COALESCE(CHAR(字段名称),") 从 ...

我想我要用 32 位版本替换这台服务器。我还有其他工作得很好。

我在 Centos

6.3 和 Centos 附带的 UnixODBC 上遇到了类似的问题,PHP 只会出现段错误。所以我跑了strace php mytest.php,发现它试图找到并打开/usr/lib64/libodbccr.so.1

然而,Centos 6.3 只有libodbccr.so.2

因此,快速而肮脏的解决方法是执行以下操作:/usr/lib64

ln -s libodbccr.so.2 libodbccr.so.1

使用风险自负!

我不能说我知道 pdo(反正我不使用)或 unixODBC 或 DB2 驱动程序中的任何问题。我不确定您的第一个平台使用的是 64 位内部版本还是 32 位内部版本,但是当Microsoft添加 64 位支持时,ODBC 发生了变化(请参阅 SQLLEN/SQLULEN 和 32/64 位平台和 64 位 ODBC)。基本上,某些 ODBC API 的类型从 SQLINTEGER 更改为 SQLLEN,SQLLEN 在 64 位构建中为 64 位,在 32 位构建中为 32 位。但是,由于没有人知道Microsoft要这样做,并且其中一些参数实际上在规范中描述为 32 位数量,因此一些 ODBC 驱动程序编写者已经为 64 位平台构建了 ODBC 驱动程序,对这些参数使用 32 位数量。显然,如果您将以一种方式构建的应用程序或驱动程序管理器与以另一种方式构建的驱动程序混合在一起,那么所有地狱都会中断丢失,并且很可能会出现段错误。因此,首先,如果您使用的是 64 位二进制文件,则需要检查您的 ODBC 驱动程序是否正确构建 - 请与 IBM 联系。

unixODBC 2.2.11 现在已经相当旧了,我知道问题已经解决,但我仍在广泛使用它,并且光标库中只有一个小问题。无论如何,您尝试了 2.2.14,问题是一样的。我怀疑这是一个unixODBC问题,但这仅仅是基于我丰富的经验,而不是因为我知道事实。

现在,假设你没有陷入上面概述的情况,你可以做很多事情。尝试在 unixODBC 中启用日志记录,然后您可以查看正在进行哪些 ODBC 调用以及哪些调用失败。您可能还会从传递的论点中获得有关可能发生的事情的线索。您可以通过将以下内容添加到 odbcinst.ini 文件来启用日志记录:

[ODBC]
Trace=yes
TraceFile=/tmp/unixodbc.log

查找对 SQLBindCol 或 SQLGetData 的调用以获取相关列。如果这不能让你得到任何地方,你可以尝试在这里粘贴它的结尾,我会看看它。

如果您可以从命令行运行PHP程序并安装gdb,则可以在gdb下运行它,它将显示问题发生位置的堆栈转储。只需执行 gdb/path/to/php 然后键入 r myscript.php 并输入即可运行它,当它出现段错误时,您可以使用 bt (backtrace) 命令来显示堆栈。这应该确定哪个代码导致了段错误,尽管不一定是该代码是错误的(例如,如果 php 传递了一个指向 10 字节缓冲区的指针,但撒谎并说它是 100 字节,则写掉末尾的代码没有错误)。