|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2003-09-15 16:49 UTC] chris at statgen dot ncsu dot edu
Description:
------------
On trying to fetch the next row from a PostgreSQL query using Pear DB you get an "undefined offset" notice from within "fetchInto" in DB_pgsql in pgsql.php.
I believe that this is caused by these two lines in DB_pgsql::freeResult:
unset($this->row[(int)$result]);
unset($this->num_rows[(int)$result]);
The problem is that the prepare used by getOne (eventually) returns the same resource number that a real query query gets (the initial query in my example code). So the row number and count for the initial query are removed from the array.
Reproduce code:
---------------
$dbuser = "postgres";
$dbpass = 'xxxxxxxx';
require_once 'DB.php';
$dsn = "pgsql://$dbuser:$dbpass@localhost/dbname";
$db = DB::connect($dsn, FALSE);
if (!DB::isError($db)) $db->setFetchMode(DB_FETCHMODE_OBJECT);
// Now execute the same query but don't fetch the result row yet.
$res1 = $db->query("SELECT 'query 1' AS col1");
if (DB::isError($res1)) exit("First query failed");
// Now issue a bunch more queries using "getOne".
for ($i = 0; $i < 20; ++$i)
{
$parms = array($i);
$val = $db->getOne("SELECT ?", $parms);
}
// Try to get the row from the query issued before the "getOne" calls.
$row = $res1->fetchRow();
if (DB::isError($row)) exit("Fetch failed for query 1 row.");
print $row->col1;
Expected result:
----------------
Running with the CLI - expect to see "query 1" get printed on the console.
Actual result:
--------------
Notice: Undefined offset: 11 in c:\www\php\DB\pgsql.php on line 289
Notice: Undefined offset: 11 in c:\www\php\DB\pgsql.php on line 290
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Wed Oct 29 07:00:01 2025 UTC |
That should fix the problem: Need feedback. Index: pgsql.php =================================================================== RCS file: /repository/pear/DB/DB/pgsql.php,v retrieving revision 1.26 diff -u -u -r1.26 pgsql.php --- pgsql.php 28 Aug 2003 14:37:36 -0000 1.26 +++ pgsql.php 16 Sep 2003 07:32:17 -0000 @@ -306,9 +306,15 @@ return false; } unset($this->prepare_tokens[(int)$result]); - unset($this->prepare_types[(int)$result]); - unset($this->row[(int)$result]); - unset($this->num_rows[(int)$result]); + if(isset($this->prepare_types[(int)$result])) { + unset($this->prepare_types[(int)$result]); + } + if(isset($this->row[(int)$result])) { + unset($this->row[(int)$result]); + } + if(isset($this->num_rows[(int)$result])) { + unset($this->num_rows[(int)$result]); + } $this->affected = 0; return true; }No, that won't work - the undefined offset error isn't coming from the freeResult member function but from the fetchInto function (when a fetchRow is called). This happens after freeResult has freed an element in the array "row" that it should not have freed. I'll see if I can be more clear.... In the reproduce code the initial query is given resource id #15. The current row number and the row count for this query is put into $this->row[15] and $this->num_rows[15]. Then I issue the other queries using getOne. The prepare used by getOne returns integer ids 1,2,3,....,15 and immediately calls freeResult on each of these ids. So when the integer value returned is 15 the "unset" lines in freeResult remove $this->row[15] and $this->num_rows[15] from the arrays - but this shouldn't be done because the initial query is still active. I then try to fetch the next (only) row of my initial query - fetchInto tries to use $this->row[15] which has already been removed and so can't get the row even though it should be able to. It's really a confusion between resource ids and integer ids. I think that the correct solution may be this something like what I've shown below. But I'm not familiar enough with this code to be sure. function freeResult($result) { if (is_resource($result)) { unset($this->row[(int)$result]); // Moved unset($this->num_rows[(int)$result]); // Moved return @pg_freeresult($result); } if (!isset($this->prepare_tokens[(int)$result])) { return false; } unset($this->prepare_tokens[(int)$result]); unset($this->prepare_types[(int)$result]); //Removed unset($this->row[(int)$result]); //Removed unset($this->num_rows[(int)$result]); $this->affected = 0; return true; }