Hi there,

we use a wrapper class to access a mysql db with php-4.0.6 running in
Apache/Linux and mysql-3.23.40.

We ran into the following problem:

Assume the following test code (sorry - rather long):


-----[ test code ]------

<?

/* defines DB_M_SERVER and so on... */
require($DOCUMENT_ROOT . "/../../htdocs_includes/www.fhh.de/config.mysql.php");

/* the database wrapper class */
class NWN_DB {
        
        // Variablen
        var $reader; // DB-Verbindung aus der gelesen wird
        var $reader_rs; // Result-ID
        var $reader_nr; // Num Rows
        
        var $writer; // DB-Verbindung in die geschrieben wird
        var $writer_rs; // Result-ID
        var $writer_li; // Last ID
        var $writer_ar; // Affected Rows
        var $writer_transaction = 0; // Grade in einer Transaktion?

        function NWN_DB () {
                // Constructor
                
                global $DB_M_server, $DB_M_user, $DB_M_pass, $DB_M_dbase;
                global $DB_S_server, $DB_S_user, $DB_S_pass, $DB_S_dbase;
                
                unset($this->reader,$this->writer);

                ( $this->writer = mysql_connect($DB_M_server, $DB_M_user, $DB_M_pass) 
) || die ("Konnte keine Verbindung zum Master herstellen!");
                mysql_select_db($DB_M_dbase, $this->writer) || die ("Konnte Master-DB 
nicht auswaehlen!");

                ( $this->reader = mysql_connect($DB_S_server, $DB_S_user, $DB_S_pass) 
) || die ("Konnte keine Verbindung zum Reader herstellen!");
                mysql_select_db($DB_S_dbase, $this->reader) || die ("Konnte Reader-DB 
nicht auswaehlen!");

                $this->reader_rs = "";
                $this->reader_nr = "";

                $this->writer_rs = "";
                $this->writer_li = "";
                $this->writer_ar = "";
        }
        
                function close () {
                // Verbindung kappen
                mysql_close($this->writer);
                mysql_close($this->reader);
                unset($this->writer);
                unset($this->reader);
        }
        
                function read ($SQL) {
                // Von den Slaves lesen, Anzahl der Zeilen im Result Set festhalten
                if ($SQL != "") {
                        // Wenn wir grade _nicht_ in einer Transaktion sind, vom 
Reader lesen
                        if ($this->writer_transaction != 1) {
                                $this->reader_rs = mysql_query($SQL, $this->reader);
                                if (! $this->reader_rs) return FALSE;
                                $this->reader_nr = mysql_num_rows($this->reader_rs);
                                return TRUE;
                        } else {
                                // Innerhalb einer Transaktion vom Writer lesen, nur 
der kann da die richtigen
                                // Daten haben. Das Result Set wird trotzdem in 
$this->reader_rs gespeichert, damit
                                // die weiteren Zugriffsfunktionen dann auch innerhalb 
der Transaktion funktionieren
                                $this->reader_rs = mysql_query($SQL, $this->writer);
                                if (! $this->reader_rs) return FALSE;
                                $this->reader_nr = mysql_num_rows($this->reader_rs);
                                return TRUE;
                        }
                } else {
                        $this->reader_rs = "";
                        $this->reader_nr = "";
                        return FALSE;
                }
        }
        
                function get () {
                // Zeile aus dem aktuellen Result Set holen
                return mysql_fetch_array($this->reader_rs);
        }
        
} //class

function bla() {

                $db2 = new NWN_DB;

                print "reader_f: " . $db2->reader."<br>";
                print "writer_f: " . $db2->writer."<br>";

                $sql = "SELECT * FROM bookmarks";
                $db2->read($sql);
                echo "table bookmarks <br>";
                while($tmp = $db2->get()) {
                        echo "db2 : $tmp[0] <br>";
                }
                $db2->close();
                //if you omit this close(), $db3 will later get the same connection
                //as db and db2
}


//lets go
$db = new NWN_DB;

print "reader1: " . $db->reader."<br>";
print "writer1: " . $db->writer."<br>";

$sql = "SELECT * FROM profile";
$db->read($sql);

bla(); //establishes the second db connection


/*
 $db3 will get a new ressource id if bla() closes its connection
 although the link is still in use by $db
 --> conclusion: the reference count for the db link does not work somehow
 probably this is related to the use of a class for the db connections
*/
$db3 = new NWN_DB;
$db3->read("SELECT * FROM mpr_attributes");

print "reader3: " . $db3->reader."<br>";
print "writer3: " . $db3->writer."<br>";

echo "table mpr_attributes <br>";
while($tmp = $db3->get()) {
        echo "db3 : $tmp[0] <br>";
}

$db3->close();

//this still returns the correct results
//although the last $db->close() tells us
//there is no more mysql connection available
echo "table profile <br>";
while($tmp = $db->get()) {
        echo "db : $tmp[0] <br>";
}

print "reader_a: " . $db->reader."<br>";
print "writer_a: " . $db->writer."<br>";

$db->close();



print "end object stuff <p><p>";


function bla2() {
        global $DB_M_server, $DB_M_user, $DB_M_pass, $DB_M_dbase;
        
        $conn2 = mysql_connect($DB_M_server, $DB_M_user, $DB_M_pass);
        mysql_select_db($DB_M_dbase,$conn2);
        $rs = mysql_query("SELECT * FROM mpr_attributes",$conn2);
        
        echo "resource2: $conn2 <br>";
        
        while ($tmp = mysql_fetch_row($rs)) {
                print "conn2: $tmp[0] <br>";
        }
        mysql_close($conn2);    
        
}


        $conn = mysql_connect($DB_M_server, $DB_M_user, $DB_M_pass);
        mysql_select_db($DB_M_dbase,$conn);

        echo "resource1: $conn <br>";

        $rs1 = mysql_query("SELECT * FROM profile",$conn);
        
        bla2();
        
        while ($tmp = mysql_fetch_row($rs1)) {
                print "conn1: $tmp[0] <br>";
        }
        
        mysql_close($conn);



//now the same procedure without a function

print "<p><p>now without a function call<p><p>";
$conn3 = mysql_connect($DB_M_server, $DB_M_user, $DB_M_pass);
mysql_select_db($DB_M_dbase,$conn3);
$rs = mysql_query("SELECT * FROM mpr_attributes",$conn3);

echo "resource3: $conn3 <br>";

while ($tmp = mysql_fetch_row($rs)) {
        print "conn3: $tmp[0] <br>";
}


$conn4 = mysql_connect($DB_M_server, $DB_M_user, $DB_M_pass);
mysql_select_db($DB_M_dbase,$conn4);

echo "resource4: $conn4 <br>";

$rs1 = mysql_query("SELECT * FROM profile",$conn4);


while ($tmp = mysql_fetch_row($rs1)) {
        print "conn1: $tmp[0] <br>";
}

mysql_close($conn3);
mysql_close($conn4);
/*
        here the close calls work as expected
        so somehow this issue has something to do with resource handling in the
        context of functions / classes
*/
?>

----[end of test code (finally)]----




the output is:
--------------

   reader1: Resource id #1
   writer1: Resource id #1
   reader_f: Resource id #1
   writer_f: Resource id #1
   table bookmarks
   db2 : 10
   db2 : 11
   db2 : 6
   db2 : 2
   db2 : 1
   db2 : 9
   db2 : 7
   db2 : 8
   reader3: Resource id #4
   writer3: Resource id #4
   table mpr_attributes
   db3 : 1
   db3 : 2
   db3 : 3
   db3 : 4
   table profile
   db : 16
   db : 13
   db : 11
   db : 12
   reader_a: Resource id #1
   writer_a: Resource id #1
   Warning: 1 is not a valid MySQL-Link resource in
   /usr/local/httpd/htdocs/www.fhh.de/test.php on line 44
   Warning: 1 is not a valid MySQL-Link resource in
   /usr/local/httpd/htdocs/www.fhh.de/test.php on line 45
   end object stuff
   
   resource1: Resource id #6
   resource2: Resource id #6
   conn2: 1
   conn2: 2
   conn2: 3
   conn2: 4
   conn1: 16
   conn1: 13
   conn1: 11
   conn1: 12
   Warning: 6 is not a valid MySQL-Link resource in
   /usr/local/httpd/htdocs/www.fhh.de/test.php on line 180
   
   now without a function call
   
   resource3: Resource id #9
   conn3: 1
   conn3: 2
   conn3: 3
   conn3: 4
   resource4: Resource id #9
   conn1: 16
   conn1: 13
   conn1: 11
   conn1: 12
---------------------

So after a mysql_close inside a function/class was executed PHP seems to
assume that the db link with the used ressource id is closed.

Since it isn't closed (we do read from apparently closed connections
above), the final mysql_close reports "not a valid MySQL-Link resource".

So somehow PHP loses information about the number of connection that
are working on the same mysql link/ressource id when mysql_close is
called within a function/class.

There are two Bugs in the Bug database which might be related to this,
but they are marked "closed":

http://bugs.php.net/bug.php?id=11201
http://bugs.php.net/bug.php?id=8634

Can someone reproduce this behaviour?

TIA, Matthias, Eike, Carsten

-- 
PHP Database Mailing List (http://www.php.net/)
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to