我有这个示例代码:
<?php
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=test_sql',
'root',
'',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$pdo->query('DROP FUNCTION IF EXISTS tst');
$pdo->query('DROP PROCEDURE IF EXISTS tst2');
$pdo->query('CREATE FUNCTION tst() RETURNS VARCHAR(5) BEGIN RETURN \'x123456\'; END');
$pdo->query('CREATE PROCEDURE tst2() BEGIN SELECT tst(); END');
$st = $pdo->prepare('CALL tst2()');
try {
$st->execute();
} catch (Throwable $ex) {
var_dump($ex->getMessage());
$st->closeCursor(); // same with unset($st)
var_dump('This is never executed');
}
所以它是一个PROCEDURE(tst2) 返回单个结果集,我在其中调用 a FUNCTION。但这(不知何故)被破坏了,因为它返回的数据对于它的子句FUNCTION来说太长了。RETURNS
当我运行这个文件时,我得到了预期的结果:
string(93) "SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'tst()' at row 1"
但后来我的问题出现了:PDOStatement 似乎“坏了”,当 PHP 尝试对它进行垃圾收集时,或者当我尝试closeCursor()(这样我可以再次进行其他查询),或者当我尝试unset它时(为了展示),然后PHP 卡住了。它永远不会到达另一个 var_dump,它只是......永远空闲?!
我在 PHP 5.6.35 和 7.1.16 和 7.2.4(都使用 mysqlnd 驱动程序 5.0.5 或 5.0.12)上遇到了这个问题。我正在使用 MySQL 5.7.21(我没有尝试其他 MySQL 版本)。
有什么线索吗?
同时,我也尝试过不使用准备好的语句(所以 using $pdo->query),甚至不使用mysqli函数:同样的问题,PHP 卡住了。
但是,通过更改过程的内容使其不尝试返回SIGNAL发生的结果集,PHP 不再卡住。所以这将“工作”(工作 = 我在我的代码中得到 SQL 异常并且我的 PHP 脚本没有被冻结)
<?php
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=test_sql',
'root',
'',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$pdo->query('DROP FUNCTION IF EXISTS tst');
$pdo->query('DROP PROCEDURE IF EXISTS tst2');
$pdo->query('CREATE FUNCTION tst() RETURNS VARCHAR(5) BEGIN RETURN \'x123456\'; END');
$pdo->query('CREATE PROCEDURE tst2() BEGIN SET @x := (SELECT tst()); END');
$st = $pdo->prepare('CALL tst2()');
try {
$st->execute();
} catch (Throwable $ex) {
var_dump($ex->getMessage());
$st->closeCursor(); // same with unset($st)
}
var_dump('end');
事实上,似乎由于 SQL 错误发生在结果集中,PDO 从 MySQL 获取结果集标头,然后获取异常并因此停止,并且永远不会“关闭”结果集(语句将保持“打开”,等待永远不会到来的数据)。
看到所有这些,我已经向 PHP 团队报告了这个错误,因为我在 mysqli 和 PDO 上得到了相同的结果,使用任何 PDO 选项,并且在一个非常具体的情况下