2012-02-09 2 views
11

У меня возникла странная проблема с php PDO и mysql.Обновление MySQL с использованием PDO и подготовленный оператор не работает

У меня есть следующая таблица:

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: Пробовал sqeeze сообщения об ошибках:

$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] => 
) 

Update 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 update специально для первый столбец каждой таблицы по обработке PDO +.

+1

Вы используете: идентификатор и изменить значение «ид», а также для идентификации строки. Вы уверены, что это то, что вы хотите сделать? – middus

+1

@middus: как он сказал: «Я переношу много кода с сервера на другой (не мой код), и он содержит много запросов, подобных этому, и у меня нет времени исправлять их по одному» –

+0

Я знаю, это не мой код. Я никогда этого не сделаю. Тем не менее, я хотел бы знать, почему он не работает на сервере, а другой - на другом. –

ответ

8

http://php.net/manual/en/pdo.prepare.php состояние:

Вы должны включить уникальный маркер параметра для каждого значения вы хотите проход, чтобы заявление при вызове PDOStatement :: Execute().Вы не можете использовать один и тот же параметр маркер с таким же именем более одного раза в подготовленный оператор, если только включен режим эмуляции.

Как это указывает на то, вероятная причина ваш код работает на одном сервере, а не другой, что PDO::ATTR_EMULATE_PREPARES отключена на сервере, который код не на. Как сказано в документации, этот атрибут эффективно устраняет ограничение, препятствующее одновременному использованию маркера параметра с тем же именем (наряду с некоторыми другими ограничениями).

+0

ну .. не ответ, на самом деле :), но спасибо –

+0

Это частичный ответ: P Я обновлю его, если я что-нибудь придумаю, но сейчас я никуда не буду. Не могу понять, почему это должно когда-либо работать, если быть честным. – Hecksa

+0

хорошо .. почему нет? Если вы попробуете исходное обновление в консоли mysql в тестовой таблице, оно работает (пример 1). Проблема возникает, только если вы замените значения на заполнители. –

-1
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 
+0

Не могли бы вы объяснить, что ваш ответ добавляет к этому вопросу или что делает ваш код? – Kermit

-2
$maker_id=1; 
$stmt = $db->prepare("UPDATE car_details SET maker_id=?"); 
$affected_rows=$stmt->execute(array($maker_id)); 
echo $affected_rows.' were affected'; 
+2

Не могли бы вы объяснить, что ваш ответ добавляет к этому вопросу или что делает ваш код? – Kermit

Смежные вопросы