从mysqldump导入无法按预期工作

时间:2013-05-03 11:27:48

标签: php mysql pdo doctrine-orm doctrine

我有一个从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。

2 个答案:

答案 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
}