-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MySQLnd: Support cursors in store/get result
This fixes two related issues: 1. When a PS with cursor is used in store_result/get_result, perform a COM_FETCH with maximum number of rows rather than silently switching to an unbuffered result set (in the case of store_result) or erroring (in the case of get_result). In the future, we might want to make get_result unbuffered for PS with cursors, as using cursors with buffered result sets doesn't really make sense. Unlike store_result, get_result isn't very explicit about what kind of result set is desired. 2. If the client did not request a cursor, but the server reports that a cursor exists, ignore this and treat the PS as if it has no cursor (i.e. to not use COM_FETCH). It appears to be a server side bug that a cursor used inside an SP will be reported to the client, even though the client cannot use the cursor. Fixes bug #64638, bug #72862, bug #77935. Closes GH-6518.
- Loading branch information
Showing
5 changed files
with
231 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--TEST-- | ||
Bug #77935: Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP with a cursor | ||
--SKIPIF-- | ||
<?php | ||
require_once('skipif.inc'); | ||
require_once('skipifconnectfailure.inc'); | ||
?> | ||
--FILE-- | ||
<?php | ||
require_once(__DIR__ . '/connect.inc'); | ||
|
||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); | ||
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket); | ||
$db->query('DROP PROCEDURE IF EXISTS testSp'); | ||
$db->query(<<<'SQL' | ||
CREATE | ||
PROCEDURE `testSp`() | ||
BEGIN | ||
DECLARE `cur` CURSOR FOR SELECT 1; | ||
OPEN `cur`; | ||
CLOSE `cur`; | ||
SELECT 1; | ||
END; | ||
SQL); | ||
|
||
$stmt = $db->prepare("CALL testSp()"); | ||
$stmt->execute(); | ||
$result = $stmt->get_result(); | ||
while ($row = $result->fetch_assoc()) { | ||
var_dump($row); | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
array(1) { | ||
[1]=> | ||
int(1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--TEST-- | ||
PS using cursor and returning multiple result sets | ||
--SKIPIF-- | ||
<?php | ||
require_once('skipif.inc'); | ||
require_once('skipifconnectfailure.inc'); | ||
?> | ||
--FILE-- | ||
<?php | ||
require_once(__DIR__ . '/connect.inc'); | ||
|
||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); | ||
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket); | ||
$db->query('DROP PROCEDURE IF EXISTS testPs'); | ||
$db->query(<<<'SQL' | ||
CREATE PROCEDURE testPs() BEGIN | ||
DECLARE testCursor CURSOR FOR SELECT 'stuff'; | ||
OPEN testCursor; | ||
CLOSE testCursor; | ||
SELECT 1 as a, 2 as b; | ||
SELECT 3 as a, 4 as b; | ||
END | ||
SQL | ||
); | ||
|
||
echo "use_result:\n"; | ||
$stmt = $db->prepare("call testPs()"); | ||
$stmt->execute(); | ||
$stmt->bind_result($v1, $v2); | ||
while ($stmt->fetch()) { | ||
var_dump($v1, $v2); | ||
} | ||
|
||
$stmt->next_result(); | ||
$stmt->bind_result($v1, $v2); | ||
while ($stmt->fetch()) { | ||
var_dump($v1, $v2); | ||
} | ||
$stmt->next_result(); | ||
|
||
echo "\nstore_result:\n"; | ||
$stmt = $db->prepare("call testPs()"); | ||
$stmt->execute(); | ||
$stmt->store_result(); | ||
$stmt->bind_result($v1, $v2); | ||
while ($stmt->fetch()) { | ||
var_dump($v1, $v2); | ||
} | ||
|
||
$stmt->next_result(); | ||
$stmt->store_result(); | ||
$stmt->bind_result($v1, $v2); | ||
while ($stmt->fetch()) { | ||
var_dump($v1, $v2); | ||
} | ||
$stmt->next_result(); | ||
|
||
echo "\nget_result:\n"; | ||
$stmt = $db->prepare("call testPs()"); | ||
$stmt->execute(); | ||
$result = $stmt->get_result(); | ||
while ($row = $result->fetch_assoc()) { | ||
var_dump($row); | ||
} | ||
|
||
$stmt->next_result(); | ||
$result = $stmt->get_result(); | ||
while ($row = $result->fetch_assoc()) { | ||
var_dump($row); | ||
} | ||
$stmt->next_result(); | ||
|
||
?> | ||
--EXPECT-- | ||
use_result: | ||
int(1) | ||
int(2) | ||
int(3) | ||
int(4) | ||
|
||
store_result: | ||
int(1) | ||
int(2) | ||
int(3) | ||
int(4) | ||
|
||
get_result: | ||
array(2) { | ||
["a"]=> | ||
int(1) | ||
["b"]=> | ||
int(2) | ||
} | ||
array(2) { | ||
["a"]=> | ||
int(3) | ||
["b"]=> | ||
int(4) | ||
} |
Oops, something went wrong.