odbc_prepare给出致命错误:允许的内存大小耗尽

时间:2017-02-09 09:18:09

标签: php ibm-midrange unixodbc

我有一个Debian服务器(64位),我想通过PHP将它连接到AS400的数据库。我已经安装了IBM i Access for Linux和unixodbc。我已经按照本教程:https://www.albertopicado.es/conexion-odbc-con-base-de-datos-db2-en-un-servidor-ibm-iseries/虽然它是西班牙语,但你可以看到我遵循的过程。 问题是我可以做一个简单的连接,如:

$query="SELECT * FROM DATABASE.TABLE WHERE ID=1;
$result=odbc_prepare($as400,$query);

返回'ok',所以我知道连接已经建立。然后我做了一个简单的odbc_prepare,如下所示:

DRIVERS............: /usr/local/etc/odbcinst.ini
SYSTEM DATA SOURCES: /usr/local/etc/odbc.ini
FILE DATA SOURCES..: /usr/local/etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

这会抛出致命错误:允许的内存大小为1048576000字节耗尽(尝试分配140707423584261字节)。

我已将php.ini文件中memory_limit的值增加到1000M,但它仍然会抛出相同的错误。我一直在网上冲浪,我发现人们有64位版本的问题,就像这篇文章:Linux odbc Fatal error: Allowed memory size但我正在执行的查询没有任何空值。

信息

odbcinst -j命令:

[iSeries Access ODBC Driver]
Description=iSeries Access for Linux ODBC Driver
Driver=/opt/ibm/iSeriesAccess/lib64/libcwbodbc.so
Setup=/opt/ibm/iSeriesAccess/lib64/libcwbodbcs.so
NOTE1=If using unixODBC 2.2.11 or later and you want the 32 and 64-bit ODBC drivers to share DSN's,
NOTE2=the following Driver64/Setup64 keywords will provide that support.
Driver64=/opt/ibm/iSeriesAccess/lib64/libcwbodbc.so
Setup64=/opt/ibm/iSeriesAccess/lib64/libcwbodbcs.so
Threading=2
DontDLClose=1
UsageCount=2

[iSeries Access ODBC Driver 64-bit]
Description=iSeries Access for Linux 64-bit ODBC Driver
Driver=/opt/ibm/iSeriesAccess/lib64/libcwbodbc.so
Setup=/opt/ibm/iSeriesAccess/lib64/libcwbodbcs.so
Threading=2
DontDLClose=1
UsageCount=1

ODBCINST.INI:

linux-gate.so.1 (0xf7763000)
libcwbcore.so => /opt/ibm/iSeriesAccess/lib/libcwbcore.so (0xf7557000)
libodbcinst.so.1 => /usr/lib/i386-linux-gnu/libodbcinst.so.1 (0xf7544000)
libdl.so.2 => /lib/i386-linux-gnu/i686/cmov/libdl.so.2 (0xf753e000)
libpthread.so.0 => /lib/i386-linux-gnu/i686/cmov/libpthread.so.0 (0xf7522000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xf7430000)
libm.so.6 => /lib/i386-linux-gnu/i686/cmov/libm.so.6 (0xf73ea000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf73cd000)
libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xf721f000)
librt.so.1 => /lib/i386-linux-gnu/i686/cmov/librt.so.1 (0xf7216000)
libltdl.so.7 => /usr/lib/i386-linux-gnu/libltdl.so.7 (0xf720a000)
/lib/ld-linux.so.2 (0xf7766000)

odbc.ini是空白的。

修改

看到iSeriesAccess驱动程序x64可能有一些错误我终于卸载了它。然后我安装了iSeriesAccess驱动程序x32。在安装新驱动程序之前,我制作了Debian multiarch并下载了ia32-libs(因为iSeriesAccess驱动程序x32缺少一些软件包)。

使用新驱动程序我收到另一个错误:
警告:odbc_connect():SQL错误:[unixODBC] [驱动程序管理器]无法打开lib'/opt/ibm/iSeriesAccess/lib/libcwbodbc.so':找不到文件,SQLConnect中的SQL状态01000。

我已经仔细检查了lib'libcwbodbc.so'是否存在。我还对lib运行命令ldd以查看是否缺少某些内容:

FRFXLLCreateLibraryContext.cpp:72:5: error: missing binary operator before token "1000000"
 #if CLOCKS_PER_SEC == 1000
     ^
<builtin>: recipe for target 'FRFXLLCreateLibraryContext.o' failed

正如您所看到的,没有遗漏的库。我错过了什么?

最后,我安装了32位版本的Debian。因为它在我看来问题依赖于64位版本的IBM I Access驱动程序。我刚刚在新装置上执行了相同的步骤,它就像一个魅力。希望它可以帮助别人。

1 个答案:

答案 0 :(得分:0)

这是#21286589的副本。仅仅因为你没有command_x值并不意味着你在使用不匹配的ABI时不会遇到问题。

这里的问题是旧的驱动程序只设置64位指针值的32位而PHP读取整个64位。这里PHP看到的值为140707423584261,以十六进制为NULL。您可以看到最后4个字节是0x7FF900000005,它是5,应该是返回的实际数据的长度。其余部分是垃圾,因为驱动程序没有改变这些字节。

正如我在Linux odbc Fatal error: Allowed memory size的回答中提到的,您需要从IBM i Access Client解决方案Linux应用程序包中获取新的ODBC驱动程序。此驱动程序遵循unixODBC自2.2.14以来使用的完整64位ABI。新的驱动程序包还包含Debian .deb软件包,因此几乎不再需要您引用的博客中的所有步骤。