使用unixODBC(DB2)+ PHP + CentOS进行段错误

时间:2012-06-07 08:06:32

标签: php pdo segmentation-fault centos unixodbc

经过2天的战斗,我试着在这里寻求帮助。我正在使用unixODBC(2.2.11)在CentOS 5.4服务器上使用DB2(iSeries)和PHP(5.3)。我想这是自PHP升级到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有关,任何想法?

3 个答案:

答案 0 :(得分:9)

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

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

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

答案 1 :(得分: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

使用风险自负!

答案 2 :(得分:5)

我不能说我知道pdo(我不使用它)或unixODBC或DB2驱动程序中的任何问题。我不确定您的电子邮件中,如果您的第一个平台使用的是64位版本或32位版本,但是当Microsoft添加64位支持时,ODBC已更改(请参阅SQLLEN/SQLULEN and 32/64 bit platforms64-bit ODBC)。基本上,一些ODBC API的类型从SQLINTEGER更改为SQLLEN,SQLLEN在64位构建中为64位,在32位构建中为32位。但是,由于没有人知道微软会这样做,并且其中一些参数实际上在规范中描述为32位数量,一些ODBC驱动程序编写者已经为这些参数使用32位数量的64位平台构建了ODBC驱动程序。显然,如果你混合使用单向构建的应用程序或驱动程序管理器与另一种方式构建的驱动程序,那么所有地狱都可能会丢失,你很可能会遇到段错误。因此,首先,如果您使用的是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并输入以运行它,当它出现segfaults时,您可以使用bt(backtrace)命令来显示堆栈。这应该确定哪个代码导致了段错误,尽管它不一定是那个错误的代码(例如,如果php传递指向10个字节的缓冲区的指针但是说它是100个字节,那么写入结尾的代码不是在错误)。