Skip to content

Commit

Permalink
Fixed bug #66878
Browse files Browse the repository at this point in the history
Keep track of whether we have fully consumed all result sets,
either using nextRowset() calls or closeCursor() and skip the
attempt to consume remaining results sets during destruction in
that case.

Especiall if closeCursor() has been used, we really shouldn't
have this sort of cross-statement inference.
  • Loading branch information
nikic committed Dec 9, 2020
1 parent ef342b0 commit fcfa7fd
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 1 deletion.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ PHP NEWS
statements). (Nikita)
. Fixed bug #78152 (PDO::exec() - Bad error handling with multiple commands).
(Nikita)
. Fixed bug #66878 (Multiple rowsets not returned unless PDO statement object
is unset()). (Nikita)

- Phar:
. Fixed bug #73809 (Phar Zip parse crash - mmap fail). (cmb)
Expand Down
7 changes: 6 additions & 1 deletion ext/pdo_mysql/mysql_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
}
#endif

if (!Z_ISUNDEF(stmt->database_object_handle)
if (!S->done && !Z_ISUNDEF(stmt->database_object_handle)
&& IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE(stmt->database_object_handle)])
&& (!(OBJ_FLAGS(Z_OBJ(stmt->database_object_handle)) & IS_OBJ_FREE_CALLED))) {
while (mysql_more_results(S->H->server)) {
Expand Down Expand Up @@ -326,6 +326,7 @@ static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
PDO_DBG_ENTER("pdo_mysql_stmt_execute");
PDO_DBG_INF_FMT("stmt=%p", S->stmt);

S->done = 0;
if (S->stmt) {
PDO_DBG_RETURN(pdo_mysql_stmt_execute_prepared(stmt));
}
Expand Down Expand Up @@ -365,6 +366,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
if (!H->emulate_prepare) {
if (mysqlnd_stmt_next_result(S->stmt)) {
pdo_mysql_error_stmt(stmt);
S->done = 1;
PDO_DBG_RETURN(0);
}

Expand All @@ -374,6 +376,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */

if (mysql_next_result(H->server)) {
pdo_mysql_error_stmt(stmt);
S->done = 1;
PDO_DBG_RETURN(0);
} else {
PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt));
Expand Down Expand Up @@ -842,6 +845,8 @@ static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt) /* {{{ */

PDO_DBG_ENTER("pdo_mysql_stmt_cursor_closer");
PDO_DBG_INF_FMT("stmt=%p", S->stmt);

S->done = 1;
if (S->result) {
mysql_free_result(S->result);
S->result = NULL;
Expand Down
3 changes: 3 additions & 0 deletions ext/pdo_mysql/php_pdo_mysql_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ typedef struct {
zend_ulong *out_length;
unsigned int params_given;
unsigned max_length:1;
/* Whether all result sets have been fully consumed.
* If this flag is not set, they need to be consumed during destruction. */
unsigned done:1;
} pdo_mysql_stmt;

extern const pdo_driver_t pdo_mysql_driver;
Expand Down
36 changes: 36 additions & 0 deletions ext/pdo_mysql/tests/bug66878.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Bug #66878: Multiple rowsets not returned unless PDO statement object is unset()
--SKIPIF--
<?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');

$pdo = MySQLPDOTest::factory();

$sql = 'SELECT 123; SELECT 42; SELECT 999';

$stmt = $pdo->query($sql);
var_dump($stmt->nextRowset());
var_dump($stmt->nextRowset());
var_dump($stmt->nextRowset());
$stmt->closeCursor();

$stmt = $pdo->query($sql);
var_dump($stmt->nextRowset());
var_dump($stmt->nextRowset());
var_dump($stmt->nextRowset());
$stmt->closeCursor();

?>
--EXPECT--
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)

0 comments on commit fcfa7fd

Please sign in to comment.