odbc_prepare gives Fatal error: Allowed memory siz

2019-02-26 23:03发布

问题:

I have a Debian server (64 bits) and I want to connect it to a AS400's database through PHP. I have installed the IBM i Access for Linux and unixodbc. I have followed this tutorial: https://www.albertopicado.es/conexion-odbc-con-base-de-datos-db2-en-un-servidor-ibm-iseries/ although it's in spanish you can see the proccess I have followed. The thing is that I can make a simple connection like:

$server= 'DRIVER={DRIVER_NAME};DATABASE=DATABASENAME;SYSTEM=IP;HOSTNAME=IP;PORT=NUMBER_OF_THE_PORT;PROTOCOL=TCPIP;';
$as400= odbc_connect($server, "username", "password");
$as400 ? echo "ok" : echo "ko";

This return 'ok' so I understand that the connection has been established. Then I make a simple odbc_prepare like the following:

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

This throws me Fatal error: Allowed memory size of 1048576000 bytes exhausted (tried to allocate 140707423584261 bytes).

I have incremented the value of memory_limit on the php.ini file to 1000M and it still throws the same error. I've been surfing on internet and I found people having problems with 64 bits versions like on this post: Linux odbc Fatal error: Allowed memory size but the query I'm executing doesn't have any null value.

Info

odbcinst -j command:

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

odbcinst.ini:

[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

odbc.ini is blank.

EDIT

Seeing that maybe the iSeriesAccess Driver x64 has some bugs I finally uninstalled it. Then I installed the iSeriesAccess Driver x32. Before installing the new driver I made my Debian multiarch and I downloaded the ia32-libs (because some packages were missing for the iSeriesAccess Driver x32).

With the new driver I get another error:
Warning: odbc_connect(): SQL error: [unixODBC][Driver Manager]Can't open lib '/opt/ibm/iSeriesAccess/lib/libcwbodbc.so' : file not found, SQL state 01000 in SQLConnect.

I have double checked that the lib 'libcwbodbc.so' exists. I also run the command ldd against the lib to see if there is something missing:

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)

As you could see there aren't missing libs. What am I missing?

SOLUTION

Finally, I installed the 32 bits version of Debian. As it looked to me the problem relied on the IBM I Access Driver of 64 bits version. I just followed the same steps on the new installation and it works like a charm. Hope it helps someone else.

回答1:

This is a duplicate of #21286589. Just because you do not have a NULL value doesn't mean you won't run in to problems when using a mis-matched ABI.

The problem here is that the old driver only sets 32-bits of the 64-bit indicator value and PHP reads the whole 64-bits. Here PHP sees the value 140707423584261, which is 0x7FF900000005 in hex. You can see the last 4 bytes are 0x00000005 which is 5 and should be the length of the actual data returned. The rest of it is garbage because the driver did not change those bytes.

As I mentioned in my answer for Linux odbc Fatal error: Allowed memory size, you will need to get the new ODBC driver from the IBM i Access Client Solutions Linux Application Package. This driver follows the full 64-bit ABI that unixODBC has used since 2.2.14. The new driver package also contains Debian .deb packages, so pretty much all the steps in the blog you referenced are no longer needed.