Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.5.0b4

Bug #17198 Loosing db-session properties after disconnect
Submitted: 2010-03-05 21:15 UTC
From: felix_ant Assigned:
Status: Open Package: MDB2_Driver_pgsql (version 1.4.1)
PHP Version: 5.2.5 OS: 1.4.1
Roadmaps: (Not assigned)    
Subscription  


 [2010-03-05 21:15 UTC] felix_ant (Toni Félix)
Description: ------------ We are working with Postgresql and using several connections. Always that we make a connection, we change some vars of the db-session (datestyle, client_encoding, ...). The problem appears when we disconnect one of them; then , the rest of the connections loose the db-sessions var that we fixed previously. We don't want to use "persistence connections", and we have read that the php-core optimizes no-persistence connections using the same instance with the same connection string. But we don't know why when you disconnect one of them, you are changing session enviroment of the rest. It could be a bug or, is a mistake of ourselves? Test script: --------------- <?php /** * test disconnect * * @package gvHIDRA * */ include_once('MDB2.php'); $dsn = array( 'phptype' => 'pgsql', 'username' => 'xxxx', 'password' => 'xxxx', 'hostspec' => 'rosa.coput.gva.es', 'database' => 'marte', ); $options = array( 'portability' => MDB2_PORTABILITY_NONE, ); $changeDateStyle = 'set session datestyle = \'sql, european\''; $query = <<<query SELECT date1 FROM example LIMIT 1 query; //First connection $con1 = MDB2::connect($dsn,$options); if (PEAR::isError($con1)) throw new Exception('Error connecting...'); $result = $con1->exec($changeDateStyle); if (PEAR::isError($result)) throw new Exception('Error setting datestyle...'); //Second connection $con2 = MDB2::connect($dsn,$options); if (PEAR::isError($con2)) throw new Exception('Error connecting...'); $result = $con2->exec($changeDateStyle); if (PEAR::isError($result)) throw new Exception('Error setting datestyle...'); //Query with connect1 $resc1 = $con1->query($query); if (PEAR::isError($resc1)){ throw new Exception('Error launching query...'); } $result1 = $resc1->fetchAll(); echo "Result with 1st connection\n"; print_r($result1); $con1->disconnect(); //Query with connect2 $resc2 = $con2->query($query); if (PEAR::isError($resc2)){ throw new Exception('Error launching query...'); } $result2 = $resc2->fetchAll(); echo "\nResult with 2on connection\n"; print_r($result2); $con2->disconnect(); ?> Expected result: ---------------- Result with 1st connection Array ( [0] => Array ( [0] => 01/01/2003 ) ) Result with 2on connection Array ( [0] => Array ( [0] => 01/01/2003 ) ) Actual result: -------------- Result with 1st connection Array ( [0] => Array ( [0] => 01/01/2003 ) ) Result with 2on connection Array ( [0] => Array ( [0] => 2003-01-01 ) )

Comments

 [2010-03-07 19:55 UTC] hschletz (Holger Schletz)
Confirmed. Since this does not happen when using native pgsql function calls instead of MDB2, it appears to be a bug in MDB2 or the driver. I don't think the connection re-usage is responsible for this. I'll investigate further.
 [2010-03-07 21:56 UTC] hschletz (Holger Schletz)
Add 'new_link' => true to your DSN array and you will get what you expect. Note that this will create a new connection instead of reusing the existing connection, so this will be more expensive. The problem is not the connection re-usage itself (as said, native pgsql functions work fine even with reused connections), but the way the connection resource gets passed around within the MDB2 code. This part of the code is a bit... complicated. I'm not sure whether this is a bug or a feature.
 [2010-03-08 14:41 UTC] felix_ant (Toni Félix)
We are working with a complex framework (gvHIDRA), and with your solution (adding 'new_link' => true to your DSN array) we could loose efficiency. For the present time, is better for us to change code and disconect all connections in the last lines of the script.
 [2010-03-09 00:57 UTC] hschletz (Holger Schletz)
I'm finally beginning to understand what is going on here. If you actually want to reuse the connection, you are following a wrong approach. The automatic connection re-usage is a feature specific to the pgsql extension. MDB2 however is designed to provide consistent behavior independent of the underlying DBMS. To reuse a connection with well-defined behavior, call MDB2::singleton() instead of MDB2::connect(). This will return a reference to the same MDB2_Driver_pgsql object. You will have to set the connection parameters (like 'datestyle' in your example) only once. Doing this after every call to singleton() won't hurt (except for the slightly increased overhead) as long as the parameters are always the same. However, do NOT call disconnect() while another reference is in use. This would affect all other references, forcing a reconnect upon the next query with default connection parameters. Explicitly calling disconnect() on non-persistent connections should rarely be necessary anyway. For the connect() and factory() methods, passing same DSN multiple times without setting new_link to TRUE may cause undefined behavior, depending on the driver. With new_link=TRUE it is safe to call disconnect() because the connections are guaranteed to be independent of each other. So I think this is not really a bug, but a symptom of undefined behavior due to wrong usage. I suggest to add a section to the documentation to make things clearer, like this: Handling multiple connections Connections with different DSN are always independent of each other. If you make multiple connections to the same DSN, you have to choose the right approach: - If you want to reuse a connection, use the singleton() method. Be careful with methods that alter the state of the object, like disconnect() or setOption(), as these changes affect all other references too. - If you need independent connections, choose connect() or factory(). You should set the new_link option in the DSN to TRUE. Otherwise, the application's behavior may be inconsistent, depending on the driver. - You should not mix the singleton() method with one of the other methods unless you really know what you are doing.