PDOStatement "зависает", когда набор результатов выдает СИГНАЛ

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

<?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

Когда возникает исключение базы данных, не пытайтесь быть умным и пытайтесь помочь базе данных очиститься. Механизм базы данных разберется в этом беспорядке. Все, что вы можете сделать, это выйти из этой операции. Я бы весь этот код завернул в транзакцию. В "улове" просто откат. В противном случае совершите. Возможно, удастся продолжить использование соединения. Это действительно зависит от того, в чем была ошибка базы данных.

Ryan Vincent 29.08.2018 22:42

@RyanVincent Я даже не могу этого сделать, так как, когда мусор PHP собирает инструкцию $st, он также застревает. Если вы попробуете этот код, ваш PHP-процесс будет выглядеть замороженным (даже вне Apache, в PHP как CLI). То же самое, если вы закомментируете closeCursor.

Xenos 29.08.2018 23:38

Здесь нет исключения, только string(22) "This is never executed", если он перемещен за пределы блока catch.

steffen 30.08.2018 00:09
PHP 7.0.30-0+deb9u1 (cli) (built: Jun 14 2018 13:50:25) ( NTS )mysql Ver 15.1 Distrib 10.1.26-MariaDB , for debian-linux-gnu (x86_64) using readline 5.2
steffen 30.08.2018 00:27

Это ненормально, если у вас вообще нет исключения, потому что PDO должен повторно выдать ошибку SQL. Возможно, он ведет себя по-другому на Maria, чем на Mysql (я также пробовал на сервере OVH, и на Linux тоже, на PHP застрял на closeCursor, пока вы не ЗАКОНЧИТЕ соединение с другим клиентом MySQL)

Xenos 30.08.2018 10:10

То же самое с mysql Ver 14.14 Distrib 5.5.43, for debian-linux-gnu (x86_64) using readline 6.2 и PHP 5.4.39-0+deb7u2 (cli) (built: Mar 25 2015 08:33:29). Работает без проблем.

steffen 30.08.2018 18:04

Тогда это может быть проблема с драйвером mysqlnd (поскольку она также возникает в mysqli, и этот mysqlnd использовался во всех моих проверках среды). Тем не менее, вы всегда должны вызывать исключение. Вы использовали MariaDB во втором тесте?

Xenos 31.08.2018 11:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
7
65
0

Другие вопросы по теме