2

mysqldump から生成された sql ダンプがあります。このファイルには、mysql バージョン固有のコメント ( /*!{MySQL version number} {Code} */) が含まれています。このブロックの後に SQL 構文エラーを挿入すると、PDO は例外をトリガーしません。

phpコード

$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 がスローされます。

4

2 に答える 2

3

私を正しい道に導いてくれたhek2mglに感謝します。

PDO は複数のクエリをサポートしていません。複数のクエリを含むステートメントを実行すると、それらは実行されますが、最初のクエリが実行された後に PDO が動作を停止するようです。スタイル コメントは/*!{MySQL version number} {Code} */MySql によって通常のクエリとして実行され、これ以降は MySql によって実行されますが、PDO によって無視されます。

示された同じエラーは、次のクエリによってトリガーされます。

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 ...
}
于 2013-05-06T07:44:27.487 に答える
1

;コメントの最後にあるためです。理由は今のところわかりません。さらに調査します...

このバグレポートを見つけました。しかし、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
}
于 2013-05-03T11:43:43.030 に答える