Недопустимый запрос PDO не возвращает ошибку

второй оператор SQL ниже возвращает ошибку в phpMyAdmin:

SET @num=2000040;
INSERT INTO artikel( artikel_nr, lieferant_nr, bezeichnung_1, bezeichnung_1 )
SELECT @num := @num +1 AS anum, 70338, f2, f3
FROM import
WHERE id >1

MySQL говорит:

#1110 - Column 'bezeichnung_1' specified twice

все правильно. Но когда я запускаю запросы в Symfony 1.4 с этой функцией:

// run sql query
// http://erisds.co.uk/symfony/snippet-creating-debugging-complex-sql-queries-in-symfony
// http://stackoverflow.com/questions/5434702/php-quick-refactoring
// param $sql:    the query to run
// param $silent: bool if errors should be ignored
// throws:        pdo error info if statement failed and $silent=false
// returns:       pdo-statement (use for looping over result rows and error messages)
public static function runQuery($sql, $silent=false)
{
  $conn = Propel::getConnection();
  $pdo_statement = $conn->prepare($sql);

  $error = null;
  try
  {
    $pdo_statement->execute();
  }
  catch (Exception $e)
  {
    $error = $e->getMessage();
  }

  if ( !$error )
  {
    $pdo_error = $pdo_statement->errorInfo();
    $error = $pdo_error[2];
  }
  if ( !$silent && $error ) throw new Exception($error);

  return $pdo_statement;
}

не ошибка. Две инструкции SQL должны быть отправлены одновременно, так как они зависят друг от друга. Ошибочный запрос построен из пользовательского ввода. Мне нужно вернуть эту ошибку, иначе я не могу сказать, была ли база данных изменена, и я не могу расскажите об этом пользователю.

знаете ли вы, почему PDO не жалуется на недопустимое утверждение, и если его нельзя заставить сделать это, как получить информацию об успехе/неудаче?

BTW запрос обновляет базу данных, если нет повторяющихся столбцов.

вот ссылка на класс PDOStatement:http://www.php.net/manual/en/class.pdostatement.php

3 ответов


это ожидаемое поведение. Поскольку существует два оператора, и первый из них действителен, вы должны использовать nextRowset ()

try
  {
    $pdo_statement->execute();
    while ($pdo_statement->nextRowset()) {/* https://bugs.php.net/bug.php?id=61613 */};
  }

источник:bugs.php.net/bug.php?id=61613


по умолчанию PDOStatement::execute() не вызывает никаких исключений, он просто возвращает false при ошибке. Вы должны установить обработку ошибок в PDO::ERRMODE_EXCEPTION через db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION).


Если у вас есть возможность использовать mysqli вместо PDO для мульти запроса вы можете использовать mysqli_multi_query. Поскольку обработка ошибок немного сложна, вот моя функция:

/**
 * Executes multiple queries at once (separated by semicolons) and discards the results
 *
 * @param string $sql
 * @throws RuntimeException if a query failed
 */
function multi_query($sql) {
    $mysqli = new mysqli('host', 'user', 'password', 'database');


    //Execute all queries
    $index = 1;
    if ($mysqli->multi_query($sql)) {
        do {
            // next_result() fails if store_result() is not called
            if ($result = $mysqli->store_result()) {
                $result->free();
            }
            $has_next = $mysqli->more_results();
            if (!$has_next)
                return; // all queries successfully executed
            $index++;
        } while ($mysqli->next_result());
    }
    // At this point, either the multi_query() has returned false - which is
    // when the first query failed - or more_results() was true, while next_result()
    // returned false - which is when a different query failed.

    $error = $mysqli->error;
    if (!$error)
        $error = $mysqli->errno ? "errno $mysqli->errno" : '(unknown error)';
    throw new RuntimeException("mysqli query $index failed: $error");
}