PHP Bugs  
php.net | support | documentation | report a bug | advanced search | search howto | statistics | login

go to bug id or search bugs for  

Bug #11993 mysql_close closes incorrect db handler
Submitted:9 Jul 2001 7:22pm UTC Modified: 29 Sep 2002 12:29am UTC
From:atiware at metasuccess dot net Assigned to:zak
Status:Closed Category:MySQL related
Version:4.1.0 OS:Debian 2.19
Votes:3 Avg. Score:5.0 ± 0.0 Reproduced:3 of 3 (100.0%)
Same Version:1 (33.3%) Same OS:1 (33.3%)
View/Vote Developer Edit Submission

[9 Jul 2001 7:22pm UTC] atiware at metasuccess dot net
debian 2.19 / mysql 3.23.37 / php 4.0.4pl1

configure section of phpinfo():
'./configure' '--with-gd' '--with-jpeg-dir' '--with-png-dir'
'--with-tiff-dir' '--disable-posix' '--enable-ftp' '--enable-calendar'
'--with-imap' '--with-mcrypt' '--with-swf=/usr/local/swf'
'--with-apache=/home/atiware/apache_1.3.14' '--enable-track-vars'
'--with-mysql=/usr/local'

the sript that reproduces the problem:
--cut here--
<?php
	define("DEEPLIMIT",10); //maximal deep of recursive calls
/*
	!! please edit this settings !!
*/
	define("MYHOST","localhost");
	define("MYPORT","3306");
	define("MYUSER","YOUR_USERNAME");
	define("MYPWD","YOUR_PASSWORD");

	/* this function reproduces the error */
	function recursive($deep,$persistent=false) {
		if ($deep<=DEEPLIMIT) {
			//down side
			if ($persistent)
				$db=mysql_pconnect(MYHOST.":".MYPORT,MYUSER,MYPWD); //creating
persistent mysql connection and storing in a local variable
			else
				$db=mysql_connect(MYHOST.":".MYPORT,MYUSER,MYPWD); //creating mysql
connection and storing in a local variable

			$res=@mysql_query("select 1 as ONE",$db); //some dummy query
			$mr=null;
			if (@mysql_num_rows($res)) {
				$mr=@mysql_fetch_array($res);
			}
			//and now write the result
			printf("%sRecursive: Deep: %s, DownSideQuery:
%s<br>\n",str_repeat(">",$deep),$deep,(int)$mr["ONE"]);

			recursive($deep+1,$persistent);

			//up side
			$res=@mysql_query("select 1 as ONE",$db); //using previously created
connection ($db), if exists ;)
			$mr=null;
			if (@mysql_num_rows($res)) {
				$mr=@mysql_fetch_array($res);
			}
			//write result again
			printf("%sRecursive: Deep: %s, UpSideQuery:
%s",str_repeat(">",$deep),$deep,(int)$mr["ONE"]);
			//error check
			if (!(int)$mr["ONE"])
				printf("&nbsp;&nbsp;<b>!?ERROR!? why 0?</b>");
			printf("<br>\n");
			@mysql_close($db); //closing mysql connection
		}
		else {
			printf("Limit occured (%s). Turning back...<br>\n",DEEPLIMIT);
		}
	}

	echo "Trying with <b>mysql_connect()</b><br>\n";
	recursive(1);

	echo "<br><br>\n\n";
	echo "Trying with <b>mysql_pconnect()</b><br>\n";
	recursive(1,true);

?>
--cut here--

the output of the script:

Trying with mysql_connect()
>Recursive: Deep: 1, DownSideQuery: 1
>>Recursive: Deep: 2, DownSideQuery: 1
>>>Recursive: Deep: 3, DownSideQuery: 1
>>>>Recursive: Deep: 4, DownSideQuery: 1
>>>>>Recursive: Deep: 5, DownSideQuery: 1
>>>>>>Recursive: Deep: 6, DownSideQuery: 1
>>>>>>>Recursive: Deep: 7, DownSideQuery: 1
>>>>>>>>Recursive: Deep: 8, DownSideQuery: 1
>>>>>>>>>Recursive: Deep: 9, DownSideQuery: 1
>>>>>>>>>>Recursive: Deep: 10, DownSideQuery: 1
Limit occured (10). Turning back...
>>>>>>>>>>Recursive: Deep: 10, UpSideQuery: 1
>>>>>>>>>Recursive: Deep: 9, UpSideQuery: 1
>>>>>>>>Recursive: Deep: 8, UpSideQuery: 1
>>>>>>>Recursive: Deep: 7, UpSideQuery: 1
>>>>>>Recursive: Deep: 6, UpSideQuery: 1
>>>>>Recursive: Deep: 5, UpSideQuery: 0  !?ERROR!? why 0?
>>>>Recursive: Deep: 4, UpSideQuery: 0  !?ERROR!? why 0?
>>>Recursive: Deep: 3, UpSideQuery: 0  !?ERROR!? why 0?
>>Recursive: Deep: 2, UpSideQuery: 0  !?ERROR!? why 0?
>Recursive: Deep: 1, UpSideQuery: 0  !?ERROR!? why 0?

Trying with mysql_pconnect()
>Recursive: Deep: 1, DownSideQuery: 1
>>Recursive: Deep: 2, DownSideQuery: 1
>>>Recursive: Deep: 3, DownSideQuery: 1
>>>>Recursive: Deep: 4, DownSideQuery: 1
>>>>>Recursive: Deep: 5, DownSideQuery: 1
>>>>>>Recursive: Deep: 6, DownSideQuery: 1
>>>>>>>Recursive: Deep: 7, DownSideQuery: 1
>>>>>>>>Recursive: Deep: 8, DownSideQuery: 1
>>>>>>>>>Recursive: Deep: 9, DownSideQuery: 1
>>>>>>>>>>Recursive: Deep: 10, DownSideQuery: 1
Limit occured (10). Turning back...
>>>>>>>>>>Recursive: Deep: 10, UpSideQuery: 1
>>>>>>>>>Recursive: Deep: 9, UpSideQuery: 1
>>>>>>>>Recursive: Deep: 8, UpSideQuery: 1
>>>>>>>Recursive: Deep: 7, UpSideQuery: 1
>>>>>>Recursive: Deep: 6, UpSideQuery: 1
>>>>>Recursive: Deep: 5, UpSideQuery: 1
>>>>Recursive: Deep: 4, UpSideQuery: 1
>>>Recursive: Deep: 3, UpSideQuery: 1
>>Recursive: Deep: 2, UpSideQuery: 1
>Recursive: Deep: 1, UpSideQuery: 1
[10 Jul 2001 9:31pm UTC] atiware at metasuccess dot net
i have tried out with the following configurations:
server1: php-4.0.6/mysql.3.23.32/apache-1.3.20/debian 2.19
server2: php-4.0.6/mysql.3.23.37/apache-1.3.20/debian 2.19

the result is the same as with php-4.0.4pl1

please check this...

thanks
ati
[11 Jul 2001 5:07am UTC] zak@php.net
Dear Ati,

When you enter a bug report, please make the script that reproduces the
error as short and simple as possible.

I do not believe that the problem that you are encountering is a bug -
you just have too many connections open at once.

Try this script:

<pre>
<?php
error_reporting (0);

function test () {
	static $count = 0;

	if (++$count < 20) {
		echo "Opening $count:";
		var_dump ($db = mysql_connect ('localhost:3306', replace_me,
replace_me));
	
		test ();

		--$count;
		echo "Closing $count:";
		var_dump (mysql_close ($db));
	} 
}

test ();
?>
</pre>

Now try it with mysql_pconnect -- does the error go away? It does for
me.

In most cases, you will only need a *single* connection to a mysql
database -- not multiple.

This may still be a bug - two or more calls to mysql_connect with the
same arguments should only result in one connection being opened. Each
call will return the same connection ID.
[11 Jul 2001 6:58am UTC] zak@php.net
Here is a refinement on this bug:

Multiple duplicate calls to mysql_connect are supposed to return the
same link ID. Each call after the first call will only return the link
ID of the first (if everything goes as planned, the connection is still
good, etc...).

    i.e.
    var_dump (mysql_connect() === mysql_connect());

Given this behavior, how should mysql_close() behave?

I would expect that calling mysql_close ($id) would close the connection
that both $id and $id2 refer to.

Behavior is not this - instead it is quite odd...

Multiple calls to mysql_close are required to close multiple duplicate
calls to mysql_connect.

    i.e.
    var_dump ($db = mysql_connect ());
    var_dump ($db = mysql_connect ()); 
    var_dump (mysql_close ($db)); 
    // Maybe this closes the default connection?
    var_dump (mysql_close ($db)); 

However, if more than two calls to mysql_connect are made, followed by a
corresponding number of calls to mysql_close, the mysql_close calls
start to fail.

    i.e.
    $max = 10;
    for ($x=0; $x<$max; ++$x) {
        var_dump ($db = mysql_connect());
    }

    for ($x=0; $x<$max; ++$x) {
        var_dump (mysql_close ($db));
    }

Now, throw change the call to mysql_close($db) to mysql_close() -
everything seems to work as expected.

However as soon as you add a call to mysql_query after the call to
mysql_close, the link will *never* die - no matter how many times you
close it.

Finally, put a call to mysql_close ($db) between the two loops. The next
call to mysql_close() will fail with an error, while subsequent calls
will succeed - once again, the link will never die.

Things get even stranger when this behavior is encountered within
recursive function calls - however, I guess that this is a side effect
of the behavior described above.

It looks like there is some complex/odd interactions happening with the
code that closes mysql links and the code that sets and uses the default
link -- however, this is quite far over my head!

Anyone else have any ideas? :)
[11 Jul 2001 1:58pm UTC] atiware at metasuccess dot net
hi zak,

thanks for your answer.

in my opinion, php must have some matrix, where you stores the number of
connect and close calls with the connection id. this will probably solve
the problem.

ps: i use these multiple connections in oop environment, where a global
connection id, is not the best idea. or?

ati

[24 Oct 2001 12:59am UTC] sniper@php.net
missing status
[20 Nov 2001 7:55pm UTC] mfischer@php.net
Can you try if the problem still persists with latest RC

http://www.php.net/~zeev/php-4.1.0RC3.tar.gz

Feedback.
[13 Dec 2001 6:26am UTC] sander@php.net
No feedback. Closing.
[13 Dec 2001 11:13am UTC] atiware at metasuccess dot net
sorry, i can not try with php4.1.0RC3. I tried out with the latest
php4.1.0, and no changes, the problem still exists.

ati
[31 Dec 2001 6:56pm UTC] zak@php.net
I will take a look at this.
[31 Dec 2001 7:15pm UTC] zak@php.net
doh.
[10 Jul 2002 5:18am UTC] georg@php.net
If you want to have always a new link, specify the 
optional parameter new_link, which is implemented since 
version 4.2.0.

See also: 
http://www.php.net/manual/en/function.mysql-connect.php
[19 Sep 2002 11:09pm UTC] zak@php.net
I need to check out how this behaves in the current CVS 
[29 Sep 2002 12:29am UTC] georg@php.net
Zak,

I already tested it. Please change the status after you detected some
possible errors, not before.

Georg

RSS feed | show source 

PHP Copyright © 2001-2009 The PHP Group
All rights reserved.
Last updated: Sat Nov 21 10:30:49 2009 UTC