I'm having a strange problem with php PDO and mysql.
I have the following table:
create table test_table ( id integer, value text );
with a single row:
insert into test_table values (1, "asdf");
when I try to update this single row with a prepared statement, I got different behaviours depending on the syntax I use:
// connection to db (common code)
$dbh = new PDO("mysql:host=localhost;dbname=test", "myuser", "mypass");
=========================================================
// WORKING
$q = 'update test_table set id=1, value='.rand(0,99999).' where id=1';
$dbh->exec($q);
=========================================================
// WORKING
$q = 'update test_table set value=:value where id=:id';
$par = array(
"id" => 1,
"value" => rand(0,99999)
);
$sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute($par);
=========================================================
// NOT WORKING
$q = 'update test_table set id=:id, value=:value where id=:id';
$par = array(
"id" => 1,
"value" => rand(0,99999)
);
$sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute($par);
In the third case, on my server, the update is not performed on the row, without any reason nor exception/error. On another server it works. I' not looking for answers like: "and so? use the first or second implementation" :)
I'm asking why the third implementation doesn't work because I'm migrating a lot of code from a server to another one (it's not my code) and it contains a lot of queries like this one and I have no time to fix them one by one. On the current server it works and on the new one it doesn't.
Why the third implementation doesn't work? Is there any kind of configuration for php/pdo/mysql which could affect this behaviour?
Thanks.
Update: Tried to sqeeze out error messages:
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
try {
// NOT WORKING
$q = 'update test_table set id=:id, value=:value where id=:id';
$par = array(
"id" => 1,
"value" => rand(0,99999)
);
$sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
print_r($sth);
print_r($dbh->errorInfo());
} catch(PDOException $e) {
echo $e->getMessage();
}
$sth->execute($par);
Executing this code on both servers (working and not working):
PDOStatement Object
(
[queryString] => update test_table set id=:id, value=:value where id=:id
)
Array
(
[0] => 00000
[1] =>
[2] =>
)
Update 2
Look at this further test:
create table test_table ( value0 text, value text );
insert into test_table values ("1", "pippo");
// NOT WORKING
$q = 'update test_table set value0=:value0, value=:value where value0=:value0';
$par = array(
"value0" => "1",
"value" => rand(0, 839273)
);
create table test_table ( value0 text, value text );
insert into test_table values ("pippo", "1");
// WORKING
$q = 'update test_table set value=:value, value0=:value0 where value=:value';
$par = array(
"value" => "1",
"value0" => rand(0, 839273)
);
Incredible, isn't it? My suspect now is that exists some special update beahaviour specifically made for the first column of every table on PDO+placeholder handling.
Yes, it is possible.
A prepared statement is a feature used to execute the same (or similar) SQL statements repeatedly with high efficiency. Prepared statements basically work like this: Prepare: An SQL statement template is created and sent to the database. Certain values are left unspecified, called parameters (labeled "?").
In layman's terms, PDO prepared statements work like this: Prepare an SQL query with empty values as placeholders with either a question mark or a variable name with a colon preceding it for each value. Bind values or variables to the placeholders. Execute query simultaneously.
http://php.net/manual/en/pdo.prepare.php states:
You must include a unique parameter marker for each value you wish to pass in to the statement when you call PDOStatement::execute(). You cannot use a named parameter marker of the same name more than once in a prepared statement, unless emulation mode is on.
As this indicates, the likely reason behind your code working on one server and not another is that PDO::ATTR_EMULATE_PREPARES
is disabled on the server which the code fails on. As the documentation says, this attribute effectively removes the restriction preventing you from using a parameter marker of the same name twice (along with some other restrictions).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With