]> granicus.if.org Git - php/commitdiff
Fixed bug #79132
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 11 Dec 2020 15:35:03 +0000 (16:35 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 11 Dec 2020 15:35:03 +0000 (16:35 +0100)
Following cmb's suggestion and replacing the counter with a check
against the bound_params HT, which ensures that both cannot go
out of sync.

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

diff --git a/NEWS b/NEWS
index b43b0a09a697c46a37c1f2616751cee8a9cfb9ef..38e86d2619be622304514f0812459661f5df519c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -59,6 +59,8 @@ PHP                                                                        NEWS
   . Fixed bug #62889 (LOAD DATA INFILE broken). (Nikita)
   . Fixed bug #67004 (Executing PDOStatement::fetch() more than once prevents
     releasing resultset). (Nikita)
+  . Fixed bug #79132 (PDO re-uses parameter values from earlier calls to
+    execute()). (Nikita)
 
 - Phar:
   . Fixed bug #73809 (Phar Zip parse crash - mmap fail). (cmb)
index 0a0526d95465b1b5a9f28e510a078105fa0eccdb..980a285c0df6d14a06f1f8e39c5cd39df9d59841 100644 (file)
@@ -229,7 +229,6 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len
        S->num_params = mysql_stmt_param_count(S->stmt);
 
        if (S->num_params) {
-               S->params_given = 0;
 #ifdef PDO_USE_MYSQLND
                S->params = NULL;
 #else
index 7d75be2adc6c56a8cce6518f63c611b45528f2ae..871b7f9c7c854c76ac16c4346d6353a9d9c4c44c 100644 (file)
@@ -387,7 +387,6 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
                                        strcpy(stmt->error_code, "HY093");
                                        PDO_DBG_RETURN(0);
                                }
-                               S->params_given++;
 
 #ifndef PDO_USE_MYSQLND
                                b = &S->params[param->paramno];
@@ -399,7 +398,7 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
                                PDO_DBG_RETURN(1);
 
                        case PDO_PARAM_EVT_EXEC_PRE:
-                               if (S->params_given < (unsigned int) S->num_params) {
+                               if (zend_hash_num_elements(stmt->bound_params) < (unsigned int) S->num_params) {
                                        /* too few parameter bound */
                                        PDO_DBG_ERR("too few parameters bound");
                                        strcpy(stmt->error_code, "HY093");
index fe7f149d84f9c702a419073967db688e62b99da9..553437829e9b21eb081557e053fbc7dec63024f3 100644 (file)
@@ -141,7 +141,6 @@ typedef struct {
        PDO_MYSQL_PARAM_BIND    *bound_result;
        my_bool                                 *out_null;
        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. */
diff --git a/ext/pdo_mysql/tests/bug79132.phpt b/ext/pdo_mysql/tests/bug79132.phpt
new file mode 100644 (file)
index 0000000..6535dbd
--- /dev/null
@@ -0,0 +1,66 @@
+--TEST--
+Bug #79132: PDO re-uses parameter values from earlier calls to execute()
+--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();
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
+test($pdo);
+echo "\n";
+$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+test($pdo);
+
+function test($pdo) {
+    $stmt = $pdo->prepare('select ? a, ? b');
+
+    $set = [
+        ['a', 'b'],
+        ['x'],      /* second parameter is missing */
+        [1 => 'y'], /* first parameter is missing */
+    ];
+
+    foreach ($set as $params) {
+        try {
+            var_dump($stmt->execute($params), $stmt->fetchAll(PDO::FETCH_ASSOC));
+        } catch (PDOException $error) {
+            echo $error->getMessage() . "\n";
+        }
+    }
+}
+
+?>
+--EXPECT--
+bool(true)
+array(1) {
+  [0]=>
+  array(2) {
+    ["a"]=>
+    string(1) "a"
+    ["b"]=>
+    string(1) "b"
+  }
+}
+SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
+SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
+
+bool(true)
+array(1) {
+  [0]=>
+  array(2) {
+    ["a"]=>
+    string(1) "a"
+    ["b"]=>
+    string(1) "b"
+  }
+}
+SQLSTATE[HY093]: Invalid parameter number
+SQLSTATE[HY093]: Invalid parameter number