PDOStatement «застревает», когда результирующий набор генерирует сигнал - PullRequest
0 голосов
/ 29 августа 2018

У меня есть этот пример кода:

<?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), который возвращает один набор результатов, в котором я называю 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).

Есть подсказка?


Между тем, я также пытался без использования подготовленных операторов (поэтому с использованием $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 и в очень конкретном случае

https://bugs.php.net/bug.php?id=76815

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...