How can I get PDO to throw an exception when executing multiple queries?
If I run the erroneous sql by itself:
$execute($ddl_partial);
$execute($insert);
Then I get the expected error:
PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 207 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Invalid column name 'other'. (SQLExecute[207] at /build/php7.0-41GaEn/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)
However, if I run some good SQL first and follow it up with the bad, then it just swallows the error and all appears fine. But looking at the database afterwards confirms all queries fail after the bad statement.
$execute($ddl_full);
$execute($insert);
$execute($drop);
$execute($ddl_partial);
$execute($insert);
I'm iterating over all the returned rowsets with while ($statement->nextRowset())
as is demonstrated in this answer, but it only prints this exactly 8 times:
array(4) {
[0] =>
string(5) "00000"
[1] =>
int(0)
[2] =>
string(24) " ((null)[0] at (null):0)"
[3] =>
string(0) ""
}
which adds up:
- 1 - first drop
- 1 - full ddl
- 3 - first inserts
- 1 - second drop
- 1 - partial ddl
- 1 - first statement from insert (second one is erroneous, so third never executes)
Why am I not getting the error message from the bad statement?
<?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);
This is a big problem for me because an exception is never thrown, so the transaction doesn't roll back and I end up with only 1/3 records inserted. I need it to be all or nothing.
I'm running Ubuntu Linux 16.04.1 with PHP 7.0.8-0ubuntu0.16.04.3 (cli) ( NTS ) connecting to Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64) using the Microsoft? ODBC Driver 13 (Preview) for SQL Server?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…