Обновление MySQL с использованием PDO и подготовленный оператор не работает
У меня возникла странная проблема с php PDO и mysql.
У меня есть следующая таблица:
create table test_table ( id integer, value text );
с одной строкой:
insert into test_table values (1, "asdf");
когда я пытаюсь обновить эту единственную строку с помощью подготовленного оператора, у меня появилось другое поведение в зависимости от используемого синтаксиса:
// 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);
В третьем случае на моем сервере обновление не выполняется в строке без каких-либо причин и исключений/ошибок. На другом сервере это работает. Я не ищу ответов вроде: "и так? Используйте первую или вторую реализацию":)
Я спрашиваю, почему третья реализация не работает, потому что я переношу много кода с сервера на другой (это не мой код), и он содержит много запросов как этот, и у меня нет времени исправлять их один за другим. На текущем сервере он работает, а на новом - нет.
Почему третья реализация не работает? Существует ли какая-либо конфигурация для php/pdo/mysql, которая может повлиять на это поведение?
Спасибо.
Update:
Пытался вызывать сообщения об ошибке:
$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);
Выполнение этого кода на обоих серверах (работающих и не работающих):
PDOStatement Object
(
[queryString] => update test_table set id=:id, value=:value where id=:id
)
Array
(
[0] => 00000
[1] =>
[2] =>
)
Обновление 2
Посмотрите на этот дополнительный тест:
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)
);
Невероятно, не так ли? Мой подозреваемый теперь заключается в том, что существует некоторое специальное обновление beahaviour, специально сделанное для первого столбца каждой таблицы при обработке указателей PDO +.
Ответы
Ответ 1
http://php.net/manual/en/pdo.prepare.php:
Вы должны включить уникальный маркер параметра для каждого значения, которое вы хотите войдите в оператор, когда вы вызываете PDOStatement:: execute(). Вы не может использовать один и тот же параметр маркера с таким же именем более одного раза в подготовленный оператор, если включен режим эмуляции.
Как это указывает, вероятная причина, по которой ваш код работает на одном сервере, а не другой, заключается в том, что PDO::ATTR_EMULATE_PREPARES
отключен на сервере, на котором сбой кода. Как сказано в документации, этот атрибут эффективно устраняет ограничение, препятствующее одновременному использованию маркера параметра с тем же именем (наряду с некоторыми другими ограничениями).
Ответ 2
try {
$db = new PDO('mysql:host=localhost;dbname=vendor_management_system', 'root', '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$fields[] = 'car_name';
$fields[] = 'model_no';
$fields[] = 'maker_id';
$fields[] = 'dealer_id';
$values[] = "testcar";
$values[] = "no#1";
$values[] = 2;
$values[] = 4;
echo SQLUpdate('car_details', $fields, $values,'car_id = 32 and car_name = "testname"',$db);
//START: SQLUpdate
//$fields = array of fields in DB
//$values = array of values respective to the $fields
function SQLUpdate($table,$fields,$values,$where,$db) {
//build the field to value correlation
$buildSQL = '';
if (is_array($fields)) {
//loop through all the fields and assign them to the correlating $values
foreach($fields as $key => $field) :
if ($key == 0) {
//first item
$buildSQL .= $field.' = ?';
} else {
//every other item follows with a ","
$buildSQL .= ', '.$field.' = ?';
}
endforeach;
} else {
//we are only updating one field
$buildSQL .= $fields.' = :value';
}
$prepareUpdate = $db->prepare('UPDATE '.$table.' SET '.$buildSQL.'
WHERE '.$where);
//execute the update for one or many values
if (is_array($values)) {
$affected_rows=$prepareUpdate->execute($values);
return $affected_rows;
} else {
$affected_rows=$prepareUpdate->execute(array(':value' => $values));
return $affected_rows;
}
//record and print any DB error that may be given
$error = $prepareUpdate->errorInfo();
if ($error[1]) print_r($error);
}
//END: SQLUpdate
Ответ 3
$maker_id=1;
$stmt = $db->prepare("UPDATE car_details SET maker_id=?");
$affected_rows=$stmt->execute(array($maker_id));
echo $affected_rows.' were affected';