From: Nikita Popov Date: Wed, 9 Dec 2020 15:30:01 +0000 (+0100) Subject: Fixed bug #66878 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fcfa7fd06b8b298b6946ec0bf2b2440dd8f5d895;p=php Fixed bug #66878 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. --- diff --git a/NEWS b/NEWS index 526100616d..d8b035b7f8 100644 --- a/NEWS +++ b/NEWS @@ -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) diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c index 1752b7f8a9..f6d460c82b 100644 --- a/ext/pdo_mysql/mysql_statement.c +++ b/ext/pdo_mysql/mysql_statement.c @@ -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)) { @@ -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)); } @@ -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); } @@ -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)); @@ -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; diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h index cfe1d68e49..7ebf875085 100644 --- a/ext/pdo_mysql/php_pdo_mysql_int.h +++ b/ext/pdo_mysql/php_pdo_mysql_int.h @@ -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; diff --git a/ext/pdo_mysql/tests/bug66878.phpt b/ext/pdo_mysql/tests/bug66878.phpt new file mode 100644 index 0000000000..f7501762ba --- /dev/null +++ b/ext/pdo_mysql/tests/bug66878.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #66878: Multiple rowsets not returned unless PDO statement object is unset() +--SKIPIF-- + +--FILE-- +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)