#25550 [Ana]: PostgreSQL query gives "undefined offset" error
| From: | chris at statgen dot ncsu dot edu | Date: | Tue, 16 Sep 2003 13:42:35 +0000 |
| Subject: | #25550 [Ana]: PostgreSQL query gives "undefined offset" error | ||
| References: | 1 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-21562@lists.php.net to get a copy of this message | ||
ID: 25550
User updated by: chris at statgen dot ncsu dot edu
Reported By: chris at statgen dot ncsu dot edu
Status: Analyzed
Bug Type: PEAR related
Operating System: Win XP
PHP Version: 4.3.1
Assigned To: cox
New Comment:
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;
}
Previous Comments:
------------------------------------------------------------------------
[2003-09-16 03:32:17] nicos@php.net
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;
}
------------------------------------------------------------------------
[2003-09-15 16:49:10] 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
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=25550&edit=1