Edit report at http://bugs.php.net/bug.php?id=44454&edit=1
ID: 44454
Comment by: gregory at tiv dot net
Reported by: mfischer@php.net
Summary: Unexpected exception thrown in foreach() statement
Status: Verified
Type: Bug
Package: PDO related
Operating System: *
PHP Version: 5.*, 6CVS (2009-04-25)
New Comment:
I have a simpler test case, one solution/explanation and one
workaround.
Tested under:
Windows - PHP 5.2.13 (cli) (built: Feb 24 2010 14:32:32)
FreeBSD - PHP 5.2.12 with Suhosin-Patch 0.9.7 (cli) (built: Feb 24 2010
23:12:45)
Demonstration code:
-------------------
<?php
#
# PDO foreach exception bug
# Demonstration code
# Author: Gregory Karpinsky, http://www.tiv.net
# 2010-05-06
print '<p>This code works OK (Exception is cleaned artificially)</p>';
$conn = new PDO( 'mysql:host=localhost', 'test', 'test' );
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$oRS = $conn->query( "select 'OK'" );
foreach ( $oRS as $row ) {
try {
$conn->query( 'Bogus SQL' );
} catch (PDOException $e) {}
if ( $conn->errorCode() ) {
$conn->query( "select 'CLEAN_PDO_ERROR'" );
}
print '<p>NO exception will be thrown.</p>';
}
print '<p>This code works OK (two separate connections)</p>';
$conn = new PDO( 'mysql:host=localhost', 'test', 'test' );
$conn2 = new PDO( 'mysql:host=localhost', 'test', 'test' );
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$oRS = $conn->query( "select 'OK'" );
foreach ( $oRS as $row ) {
try {
$conn2->query( 'Bogus SQL' );
} catch (PDOException $e) {}
print '<p>NO exception will be thrown.</p>';
}
print '<p>This code throws unexpected exception in foreach</p>';
$conn = new PDO( 'mysql:host=localhost', 'test', 'test' );
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$oRS = $conn->query( "select 'OK'" );
foreach ( $oRS as $row ) {
try {
$conn->query( 'Bogus SQL' );
} catch (PDOException $e) {}
print '<p>Exception will be thrown after this...</p>';
}
?>
Previous Comments:
------------------------------------------------------------------------
[2009-04-25 17:16:14] mfischer@php.net
Using Windows snapshots, verified that the bug still exists in
5.2.10-dev and 5.3.0RC2-dev . Cannot test with 6.0.0-dev, the php.exe
doesn't even properly start.
------------------------------------------------------------------------
[2009-04-25 14:57:23] jani@php.net
Does this still exist? If so, update the version properly.. ;)
------------------------------------------------------------------------
[2008-07-03 16:44:39] uw@php.net
Correction:
emulated prepared statements - not using traversable - Issue exists
emulated prepared statement - using traversable - Issue exists
------------------------------------------------------------------------
[2008-07-03 16:37:49] uw@php.net
No comment on the cause just some observations. Issue exists with SQLite
as well.
PHP 5.3 CVS
MySQL results:
emulated prepared statements - not using traversable - OK
emulated prepared statement - using traversable - Issue exists
native prepared statements - not using traversable - OK
native prepared statements - using traversable - OK
SQLite:
emulated prepared statements - not using traversable - Issue exists
emulated prepared statement - using traversable - Issue exists
"not using traversable":
$stmt = $db->query('SELECT a, b FROM test');
while ($row = $stmt->fetch()) {
try {
$db->exec('INSERT INTO test(a, b) VALUES (1, 1)');
} catch (Exception $e) {
printf("while loop\n");
}
}
"using traversable":
$stmt = $db->query('SELECT a, b FROM test');
foreach ($stmt as $row) {
try {
$db->exec('INSERT INTO test(a, b) VALUES (1, 1)');
} catch (Exception $e) {
printf("foreach\n");
}
}
------------------------------------------------------------------------
[2008-03-17 14:11:44] mfischer@php.net
Description:
------------
I'm using the SQL SELECT result of an PDO query directly in an foreach()
loop (via it's iterator capability).
Within this loop I'm doing INSERTs and they violate integrity
constraints and thus PDO throws an exception.
I'm catching and basically suppressing the exception. However when the
foreach() loop is finished, an exception gets thrown with the line where
the foreach() statement is declared.
It seems internally the thrown but silently ignored exception has queued
and suddenly being let loose when the foreach() loop finishes.
It doesn't matter whether the SELECT-statement fetches the data from the
table where it is inserted or not, this is just done to make the example
simpler.
I've also tested with php5.3-win32-200803170030 and it's the same
behavior.
It seems to be an similar issue like #39345, but in my case I'm using
the mysql driver and the exception is within my PHP source.
Reproduce code:
---------------
<?php
$oPdo = new PDO('mysql:host=db01;dbname=test', 'test', 'test');
$oPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$oPdo->query('DROP TABLE IF EXISTS test');
$sSqlCreate = <<<SQL
CREATE TABLE test (
a bigint(20) unsigned NOT NULL,
b bigint(20) unsigned NOT NULL,
UNIQUE KEY unique_ref (a,b)
) ENGINE=MyISAM;
SQL;
$oPdo->query($sSqlCreate);
$oPdo->query('TRUNCATE test');
$oPdo->query('INSERT INTO test(a, b) VALUES(1, 1)');
$oResult = $oPdo->query('SELECT * FROM test');
foreach ($oResult as $aRow) {
try {
$oPdo->query('INSERT INTO test(a, b) VALUES(1, 1)');
} catch (Exception $e) { }
}
?>
Expected result:
----------------
Don't throw an exception:
$ php reproduce_pdo_bug.php
# 0
# 1
$
Actual result:
--------------
$ php reproduce_pdo_bug.php
# 0
# 1
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062
Duplicate entry '1-1' for key 1 in reproduce_pdo_bug.php on line 20
Call Stack:
0.0002 58460 1. {main}() reproduce_pdo_bug.php:0
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/bug.php?id=44454&edit=1