ID: 20298 Comment by: t-yonetani+php at ergobrains dot co dot jp Reported By: phpbug at tab1 dot clara dot co dot uk Status: Verified Bug Type: ODBC related Operating System: * PHP Version: 5CVS, 4CVS (2004-04-13) New Comment:
Here's a patch written according to phpbugs at kevin dot offwhite dot net's suggestion(I hope space and tabs won't be damanged). We're using a similar version(just by replacing SQLGetInfo() with SQLGetConnectAttr()) on a spare machine, and odbc_pconnect() seems to be working so far. Uncommenting out the code for fixing #15758 is a bit scary, but I believe it should be OK. Index: php_odbc.c =================================================================== RCS file: /repository/php-src/ext/odbc/php_odbc.c,v retrieving revision 1.143.2.12 diff -u -r1.143.2.12 php_odbc.c --- php_odbc.c 14 Jun 2003 03:37:30 -0000 1.143.2.12 +++ php_odbc.c 27 Jul 2005 08:47:05 -0000 @@ -2156,6 +2156,29 @@ } /* }}} */ +/* {{{ is_connection_dead */ +static int is_connection_dead(odbc_connection *db_conn) +{ +#if defined(HAVE_IBMDB2) +#else + UCHAR d_name[32]; + SWORD len; +#endif + SQLINTEGER dead; + RETCODE ret; + +#if defined(HAVE_IBMDB2) + ret = SQLGetConnectAttr(db_conn->hdbc, SQL_ATTR_CONNECTION_DEAD, &dead, + 0, NULL); +#else + ret = SQLGetInfo(db_conn->hdbc, SQL_DATA_SOURCE_READ_ONLY, d_name, + sizeof(d_name), &len); + dead = len == 0; +#endif + return ret != SQL_SUCCESS || dead; +} +/* }}} */ + /* Persistent connections: two list-types le_pconn, le_conn and a plist * where hashed connection info is stored together with index pointer to * the actual link of type le_pconn in the list. Only persistent @@ -2282,23 +2305,13 @@ * check to see if the connection is still in place (lurcher) */ if(ODBCG(check_persistent)){ - RETCODE ret; - UCHAR d_name[32]; - SWORD len; - - ret = SQLGetInfo(db_conn->hdbc, - SQL_DATA_SOURCE_READ_ONLY, - d_name, sizeof(d_name), &len); - - if(ret != SQL_SUCCESS || len == 0) { + if(is_connection_dead(db_conn)) { zend_hash_del(&EG(persistent_list), hashed_details, hashed_len + 1); - /* Commented out to fix a possible double closure error - * when working with persistent connections as submitted by - * bug #15758 - * - * safe_odbc_disconnect(db_conn->hdbc); - * SQLFreeConnect(db_conn->hdbc); + /* + * now that we know the connection is dead, just free + * the DBC handle without issuing SQLDisconnect(). */ + SQLFreeConnect(db_conn->hdbc); goto try_and_get_another_connection; } } Previous Comments: ------------------------------------------------------------------------ [2005-04-25 17:19:56] mwilmes at avc dot edu I am running Apache 2.0.45 and PHP 4.3.11 on Win 2K3 Server. I was hoping this was only a problem with earlier versions of PHP. My only indcation is that this happens in the mornings when I come in, and I would have to restart Apache to clear things up. Our Oracle server (connected to using ODBC) reboots for its backup, so my server has a dead ODBC handle when we get in. Until it is fixed or we develop a workaround, I guess I'll be switching to odbc_connect. ------------------------------------------------------------------------ [2004-06-04 22:06:49] phpbugs at kevin dot offwhite dot net Well, after some additional research I have turned up what I think is the exact cause of the bug, but I don't feel qualified to implement the solution. In the php code, at line 2271 in php_odbc.c ( http://lxr.php.net/source/php-src/ext/odbc/php_odbc.c#2271 ), php calls SQLGetInfo() passing a parameter of SQL_DATA_SOURCE_READ_ONLY to try and determine if the connection is alive or not. While this may work in some odbc drivers, it is not the "official" way of asking if the connection is dead. According to my driver supplier ( http://www-912.ibm.com/o_dir/odbcforum.nsf/8178b1c14b1e9b6b8525624f0062fe9f/B0CFDBA3D8DBAC0F86256EA80077D2B9?OpenDocument ) and the Microsoft's ODBC Programmer's reference ( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcodbc_connection_pooling.asp ), the correct method is to use SQLGetConnectAttr() to check the Attribute SQL_ATTR_CONNECTION_DEAD. Steps to reproduce: 1) Use PHP's odbc_pconnect() function with the iSeries ODBC Driver for Linux. 2) Allow the connection to idle long enough for the Server to disconnect. 3) Try and use the connection which was disconnected by the server. Expected result: 1) PHP calls SQLGetConnectAttr() to check SQL_ATTR_CONNECTION_DEAD, which returns SQL_ERROR. 2) PHP removes the connection from its internal list, creates a new persistent connection, and returns that new connection to the php script 3) call to odbc_exec() succeeds. Actual result: 1) PHP calls SQLGetInfo() to check SQL_DATA_SOURCE_READ_ONLY, which returns SQL_SUCCESS 2) PHP believes this to be a valid connection, and returns this connection to the php script 3) call to odbc_exec() fails. ------------------------------------------------------------------------ [2004-04-02 10:48:58] phpbugs at kevin dot offwhite dot net I'm seeing this problem on a Red Hat 9 system running PHP 4.3.5 on Apache 2.0. I have check_persistent and allow_persistent On, and phpinfo() reports 1 active persistent link. I'm not clear if the problem is in the ODBC Driver not reporting back to php that the server has terminated the link, or if PHP is not properly checking if the persistent link needs to be re-established, but I thought it wouldn't hurt to report the bug here and see what we can come up with. An interesting thing is that while phpinfo() reports only one persistent link, a netstat on the webserver shows 6 connections to the database server. When I load the page with the odbc_pconnect call, it will alternate between working and not working from pageload to pageload, so it seems that some of those connections are good and others are not, and php is not removing the bad connection from the hash list. The error message I get is: Warning: odbc_exec(): SQL error: [unixODBC][IBM][iSeries Access ODBC Driver]Communication link failure. comm rc=10054 - CWBCO1047 - The iSeries server application disconnected the connection, SQL state 08S01 in SQLExecDirect in /usr/local/apache/htdocs/test.php on line 15 ------------------------------------------------------------------------ [2003-12-02 04:47:47] phpbug at tab1 dot clara dot co dot uk okay this was tested with: php4-win32-STABLE-200312020930 1st run: resource(2) of type (odbc link persistent) followed by the correct query results 2nd run (after killing db connection): resource(1) of type (odbc link persistent) Warning: odbc_exec(): SQL error: [Informix][Informix ODBC Driver]Communication link failure., SQL state 08S01 in SQLExecDirect in C:\InetPub\wwwroot\test.php on line 8 ------------------------------------------------------------------------ [2003-12-01 03:00:17] [EMAIL PROTECTED] Can you add 'var_dump($dbconn);' after that odbc_pconnect() call..? What does it output? (in the re-run) ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/20298 -- Edit this bug report at http://bugs.php.net/?id=20298&edit=1