Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions ext/mysqli/tests/gh12107.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
--TEST--
GH-12107 (When running a stored procedure (that returns a result set) twice, PHP crashes)
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once 'skipifconnectfailure.inc';
?>
--FILE--
<?php
require_once 'connect.inc';

$mysqli = new mysqli("$host:$port", $user, $passwd, $db);

$sql = <<<SQL
CREATE PROCEDURE `gh12107`()
BEGIN
SELECT "hello world";
END;
SQL;
$mysqli->query($sql);

echo "Start or run 1\n";
$stmt = $mysqli->prepare("call `gh12107`()");
$stmt->execute();
$stmt->bind_result($output);
var_dump($stmt->fetch());
var_dump($output);
unset($output);
echo "End of run 1\n";

echo "Start or run 2\n";
$stmt->execute();
$stmt->bind_result($output);
var_dump($stmt->fetch());
var_dump($output);
echo "End of run 2\n";

?>
--CLEAN--
<?php
require_once 'connect.inc';
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());

if (!mysqli_query($link, "DROP PROCEDURE IF EXISTS gh12107"))
printf("[c002] Cannot drop procedure, [%d] %s\n", mysqli_errno($link), mysqli_error($link));

mysqli_close($link);
?>
--EXPECT--
Start or run 1
bool(true)
string(11) "hello world"
End of run 1
Start or run 2
bool(true)
string(11) "hello world"
End of run 2
5 changes: 4 additions & 1 deletion ext/mysqlnd/mysqlnd_ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,11 @@ MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, const enum_my
Executed, but the user hasn't started to fetch
This will clean also the metadata, but after the EXECUTE call we will
have it again.
stmt->result may be freed by free_stmt_result, transitively called from flush.
*/
stmt->result->m.free_result_buffers(stmt->result);
if (stmt->result) {
stmt->result->m.free_result_buffers(stmt->result);
}

stmt->state = MYSQLND_STMT_PREPARED;
} else if (stmt->state < MYSQLND_STMT_PREPARED) {
Expand Down