Как я могу заставить PDO генерировать исключение при выполнении нескольких запросов?
Если я запускаю ошибочный sql сам по себе:
$execute($ddl_partial);
$execute($insert);
Затем я получаю ожидаемую ошибку:
Неустранимая ошибка PHP: Uncaught PDOException: SQLSTATE [42S22]: Столбец не найден: 207 [Microsoft] [Драйвер ODBC 13 для SQL Server] [SQL Server] Недопустимое имя столбца «другое». (SQLExecute[207] в /build/php7.0-41GaEn/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)
Однако, если я сначала запускаю хороший SQL, а затем плохой, он просто проглатывает ошибку, и все выглядит нормально. Но просмотр базы данных впоследствии подтверждает, что все запросы терпят неудачу после неверного утверждения.
$execute($ddl_full);
$execute($insert);
$execute($drop);
$execute($ddl_partial);
$execute($insert);
Я перебираю все возвращенные наборы строк с помощью while ($statement->nextRowset())
, как продемонстрировано в этом ответе, но это печатается ровно 8 раз. :
array(4) { [0] => string(5) "00000" [1] => int(0) [2] => string(24) " ((null)[0] at (null):0)" [3] => string(0) "" }
что складывается:
- 1 - первая капля
- 1 - полный ddl
- 3 - первые вставки
- 1 - второе падение
- 1 - частичный ddl
- 1 - первый оператор из вставки (второй ошибочен, поэтому третий никогда не выполняется)
Почему я не получаю сообщение об ошибке из неверного оператора?
<?php
$hostname = 'microsoftsql.example.com';
$database = 'mydb';
$username = 'user';
$password = 'P@55w0rd';
// https://www.microsoft.com/en-us/download/details.aspx?id=50419
$driver = 'ODBC Driver 13 for SQL Server';
$pdo = new PDO("odbc:Driver=$driver;
Server=$hostname;
Database=$database",
$username,
$password
);
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$pdo->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$drop = "DROP TABLE testerino;";
$ddl_full = "
CREATE TABLE testerino (
value VARCHAR(10),
other VARCHAR(10)
);
";
$ddl_partial = "
CREATE TABLE testerino (
value VARCHAR(10)
);
";
$insert = "
INSERT INTO testerino (value)
VALUES ('first');
INSERT INTO testerino (value, other)
VALUES ('second', 'another');
INSERT INTO testerino (value)
VALUES ('third');
";
$execute = function (String $sql) use ($pdo) {
$pdo->beginTransaction();
try {
$statement = $pdo->prepare($sql);
$statement->execute();
do {
/* https://bugs.php.net/bug.php?id=61613 */
var_dump($statement->errorInfo());
} while ($statement->nextRowset());
$pdo->commit();
} catch (PDOException $e) {
$pdo->rollBack();
throw $e;
} finally {
$statement->closeCursor();
}
};
$execute($drop); // not needed first time
$execute($ddl_full);
$execute($insert);
$execute($drop);
$execute($ddl_partial);
$execute($insert);
Это большая проблема для меня, потому что исключение никогда не генерируется, поэтому транзакция не откатывается, и в итоге я вставляю только 1/3 записей. Мне нужно, чтобы было все или ничего.
Я использую Ubuntu Linux 16.04.1 с PHP 7.0.8-0ubuntu0.16.04.3 (cli) (NTS), подключаясь к Microsoft SQL Server 2012 (SP3) (KB3072779) — 11.0.6020.0 (X64), используя Драйвер Microsoft® ODBC 13 (предварительная версия) для SQL Server®
$insert
, то увидите, что оно содержит 3 оператора вставки. - person Jeff Puckett   schedule 18.10.2016PDO::ERRMODE_EXCEPTION
, который у меня есть, или путем повторенияwhile ($statement->nextRowset())
, что тоже не работает для меня. Кроме того, выполнение запросов в пакетном режиме необходимо для повышения производительности. Выполнение операторов по одному работает нормально, но для некоторых целей занимает слишком много времени. - person Jeff Puckett   schedule 18.10.2016