2

经过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 是否有任何列长度限制或错误?这个网络应用程序工作得很好,然后我遇到了这个问题..

顺便说一句,我使用更新的 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有关,知道吗?

4

3 回答 3

9

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

解决方法: SELECT COALESCE(CHAR(fieldname),'') FROM ...

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

于 2012-11-30T13:48:49.467 回答
6

我在带有 Vertica 6 的 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

使用风险自负!

于 2013-01-09T21:14:47.477 回答
5

我不能说我知道 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 字节,那么最后写出的代码不是有过错)。

于 2012-06-07T12:19:15.570 回答