У меня странная проблема с 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, которая может повлиять на это поведение?
Благодарю.
Обновление: вызывается сообщение об ошибках sqeeze out:
$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 + placeholder.
http://php.net/manual/en/pdo.prepare.php :
Вы должны включить уникальный маркер параметра для каждого значения, которое вы хотите передать в оператор, когда вы вызываете PDOStatement :: execute (). Вы не можете использовать один и тот же параметр маркера одного и того же имени более одного раза в подготовленном операторе, если не включен режим эмуляции.
Как видно из этого, вероятная причина, по которой ваш код работает на одном сервере, а не другой, заключается в том, что PDO::ATTR_EMULATE_PREPARES
отключен на сервере, с которого происходит сбой кода. Как сказано в документации, этот атрибут эффективно устраняет ограничение, препятствующее одновременному использованию маркера параметра с тем же именем (наряду с некоторыми другими ограничениями).
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
$maker_id=1; $stmt = $db->prepare("UPDATE car_details SET maker_id=?"); $affected_rows=$stmt->execute(array($maker_id)); echo $affected_rows.' were affected';