]> granicus.if.org Git - php/commitdiff
Fixed bug #66878
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 9 Dec 2020 15:30:01 +0000 (16:30 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 9 Dec 2020 15:38:22 +0000 (16:38 +0100)
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.

NEWS
ext/pdo_mysql/mysql_statement.c
ext/pdo_mysql/php_pdo_mysql_int.h
ext/pdo_mysql/tests/bug66878.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 526100616d44803262649930df3a9972f8683837..d8b035b7f8903236ec30d89a948db58ffcc55b69 100644 (file)
--- 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)
index 1752b7f8a93de5b49d39d1d5bf17f87d08f59737..f6d460c82bd0bf7a7cea73fd9fdbe12799b60f46 100644 (file)
@@ -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;
index cfe1d68e495dee6f21b0d28cf51305805e81acc5..7ebf875085c4d4942363c4c6c13365e4d6dfe5e0 100644 (file)
@@ -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 (file)
index 0000000..f750176
--- /dev/null
@@ -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)