我有一个从mysqldump生成的sql转储。此文件包含特定于mysql版本的注释(/*!{MySQL version number} {Code} */
)。
如果我在此块之后插入sql语法错误,则PDO不会触发异常。
php code
$sql = file_get_contents('FooBar.sql');
$pdo = new \PDO('mysql:host=localhost;dbname=FooBar', 'root');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->exec($sql);
FooBar.sql
/*!40101 SET @Foo='Bar' */;
ERROR
INSERT INTO Foo VALUES ('Bar');
执行此操作时不会导致任何异常或错误。如果我删除/*!40101 SET @Foo='Bar' */;
语句,或者在行上移动错误,则抛出PDOException。
答案 0 :(得分:3)
感谢hek2mgl让我走上了正确的道路。
PDO不支持多个查询。如果执行包含多个查询的语句,它们将被执行,但似乎PDO在执行第一个查询后停止运行。 /*!{MySQL version number} {Code} */
样式注释由MySql作为常规查询执行,PDO忽略此后的任何内容,即使它由MySql执行。
指示的相同错误将由以下查询触发:
SET @Foo='Bar';
ERROR
INSERT INTO Foo VALUES ('Bar');
为了使用PDO工作,我需要拆分语句。
$sql = file_get_contents('FooBar.sql');
$lines = explode(';', $sql);
$pdo = new \PDO('mysql:host=localhost;dbname=FooBar', 'root');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
foreach ($lines as $line) {
$trimmedLine = trim($line, " \t\n\r\0\x0B");
if (strlen($trimmedLine) > 0) {
$pdo->exec($trimmedLine.';');
}
}
编辑:
另一种解决方案是使用pdo预处理语句。
$sql = file_get_contents('FooBar.sql');
$pdo = new \PDO('mysql:host=localhost;dbname=FooBar', 'root');
$stmt = $pdo->prepare($sql);
$stmt->execute();
do {
... Do stuff ...
} while ($stmt->nextRowset());
if ($stmt->errorCode() != '00000') {
... Handle error ...
}
答案 1 :(得分:1)
这是因为评论末尾的;
。我现在不知道为什么。将进一步调查......
找到此bug report。但是不要指望char编码是一个问题因为我使用wireshark
调查网络流量并且MySQL返回语法错误(如预期的那样)。仍然不知道为什么PDO不处理这个正确。
解决方法是使用似乎正确处理此问题的Mysqli
。以下示例演示了这一点:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'secret');
$result = $pdo->query('
SELECT 1 AS num;
ERROR
SELECT 1 AS num;
');
if(!$result) {
var_dump($pdo->errorInfo); // silence ...
}
$mysqli = new Mysqli('localhost', 'root', 'user', 'secret');
$result = $mysqli->query('
SELECT 1 AS num;
ERROR
SELECT 1 AS num;
');
if(!$result) {
print( $mysqli->error);
// Output: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ERROR SELECT 1 AS num' at line 2
}