]> granicus.if.org Git - php/commitdiff
Backport fix for 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>
Thu, 10 Dec 2020 08:58:47 +0000 (09:58 +0100)
Given the number of duplicates this bug report had, it seems
worthwhile to fix this on PHP-7.4 as well.

Cherry-pick of 106e7e4bca7c0fd975eb219b18e3c34957ba8657.

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 d3c5e521396ce6257596f810cbf1892f69dfa3a8..60310b2692bedf221750035be69b258c8ff9f829 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,8 @@ PHP                                                                        NEWS
     statements). (Nikita)
   . Fixed bug #78152 (PDO::exec() - Bad error handling with multiple commands).
     (Nikita)
+  . Fixed bug #70066 (Unexpected "Cannot execute queries while other unbuffered
+    queries"). (Nikita)
 
 - Phpdbg:
   . Fixed bug #76813 (Access violation near NULL on source operand). (cmb)
index 93f7254a7c736a14ae313e05ba0bffe792037774..e737537f5c59c32a262adf199a266c706d9edbd2 100644 (file)
@@ -82,7 +82,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 2d8c4698e76eb44ba9ad3aa0c72e42064ece4700..c5c04adf8a7a1fd7c8b49aaa9560a4a83f03617a 100644 (file)
@@ -203,18 +203,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 b2c37dcfecda69709a0267fa55732120aee94372..beb559f0c1e57807cbe45982c08e5d854fcecf42 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
 
 
@@ -58,7 +56,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;
        }
 
@@ -352,7 +350,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
        PDO_DBG_INF_FMT("stmt=%p", S->stmt);
 
 #if PDO_USE_MYSQLND
-       if (!H->emulate_prepare) {
+       if (S->stmt) {
                if (!mysqlnd_stmt_more_results(S->stmt)) {
                        PDO_DBG_RETURN(0);
                }
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===