]> granicus.if.org Git - php/commitdiff
Fixed bug #70066
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 9 Dec 2020 16:24:30 +0000 (17:24 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 9 Dec 2020 16:24:30 +0000 (17:24 +0100)
If we fall back to emulated prepared statements, destroy S->stmt,
so the code doesn't get confused about which mode we're in.

NEWS
ext/mysqlnd/mysqlnd_libmysql_compat.h
ext/pdo_mysql/mysql_driver.c
ext/pdo_mysql/mysql_statement.c
ext/pdo_mysql/tests/bug70066.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index d8b035b7f8903236ec30d89a948db58ffcc55b69..654544bb8fb1a3d8461f5ca8af030fea27a5088d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -45,6 +45,8 @@ PHP                                                                        NEWS
     (Nikita)
   . Fixed bug #66878 (Multiple rowsets not returned unless PDO statement object
     is unset()). (Nikita)
+  . Fixed bug #70066 (Unexpected "Cannot execute queries while other unbuffered
+    queries"). (Nikita)
 
 - Phar:
   . Fixed bug #73809 (Phar Zip parse crash - mmap fail). (cmb)
index df4b96eec32f5a1d325185f63f4987df5799f94d..092659e9dd19a32e984b870d1508439a5a7d9d59 100644 (file)
@@ -80,7 +80,7 @@
 #define mysql_stmt_param_count(s)              mysqlnd_stmt_param_count((s))
 #define mysql_stmt_num_rows(s)                 mysqlnd_stmt_num_rows((s))
 #define mysql_stmt_insert_id(s)                        mysqlnd_stmt_insert_id((s))
-#define mysql_stmt_close(s)                            mysqlnd_stmt_close((s))
+#define mysql_stmt_close(s)                            mysqlnd_stmt_close((s), 0)
 #define mysql_stmt_bind_param(s,b)             mysqlnd_stmt_bind_param((s), (b))
 #define mysql_stmt_bind_result(s,b)            mysqlnd_stmt_bind_result((s), (b))
 #define mysql_stmt_errno(s)                            mysqlnd_stmt_errno((s))
index eafd28463fefa1b91010ad77f6094803c45ec595..764c453438ef4d830de825849e5ae62e967d4b8a 100644 (file)
@@ -201,18 +201,17 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len
        }
 
        if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
+               if (nsql) {
+                       efree(nsql);
+               }
                /* TODO: might need to pull statement specific info here? */
                /* if the query isn't supported by the protocol, fallback to emulation */
                if (mysql_errno(H->server) == 1295) {
-                       if (nsql) {
-                               efree(nsql);
-                       }
+                       mysql_stmt_close(S->stmt);
+                       S->stmt = NULL;
                        goto fallback;
                }
                pdo_mysql_error(dbh);
-               if (nsql) {
-                       efree(nsql);
-               }
                PDO_DBG_RETURN(0);
        }
        if (nsql) {
index f6d460c82bd0bf7a7cea73fd9fdbe12799b60f46..005f5890ab3c585e824422a3398aac2783e7ca71 100644 (file)
 #ifdef PDO_USE_MYSQLND
 #      define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt)
 #      define pdo_free_bound_result(res) zval_ptr_dtor(res.zv)
-#      define pdo_mysql_stmt_close(stmt) mysqlnd_stmt_close(stmt, 0)
 #else
 #      define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
 #      define pdo_free_bound_result(res) efree(res.buffer)
-#      define pdo_mysql_stmt_close(stmt) mysql_stmt_close(stmt)
 #endif
 
 
@@ -56,7 +54,7 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
                S->einfo.errmsg = NULL;
        }
        if (S->stmt) {
-               pdo_mysql_stmt_close(S->stmt);
+               mysql_stmt_close(S->stmt);
                S->stmt = NULL;
        }
 
@@ -363,7 +361,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
        }
 
 #ifdef PDO_USE_MYSQLND
-       if (!H->emulate_prepare) {
+       if (S->stmt) {
                if (mysqlnd_stmt_next_result(S->stmt)) {
                        pdo_mysql_error_stmt(stmt);
                        S->done = 1;
diff --git a/ext/pdo_mysql/tests/bug70066.phpt b/ext/pdo_mysql/tests/bug70066.phpt
new file mode 100644 (file)
index 0000000..54660fb
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Bug #70066: Unexpected "Cannot execute queries while other unbuffered queries"
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+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();
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
+
+$db = $pdo->query('SELECT DATABASE()')->fetchColumn(0);
+// USE is not supported in the prepared statement protocol,
+// so this will fall back to emulation.
+$pdo->query('USE ' . $db);
+
+?>
+===DONE===
+--EXPECT--
+===DONE===