]> granicus.if.org Git - php/commitdiff
Move fetch_all implementation out of mysqlnd
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 18 Dec 2020 11:13:17 +0000 (12:13 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 18 Dec 2020 11:27:30 +0000 (12:27 +0100)
There doesn't seem to be any compelling reason to implement this
in mysqlnd rather than mysqli. It's just a loop over fetch_into.

This makes the function available under libmysqlclient as well,
and thus fixes bug #79372.

12 files changed:
NEWS
UPGRADING
ext/mysqli/mysqli.stub.php
ext/mysqli/mysqli_arginfo.h
ext/mysqli/mysqli_nonapi.c
ext/mysqli/tests/bug75434.phpt
ext/mysqli/tests/mysqli_class_mysqli_result_interface.phpt
ext/mysqli/tests/mysqli_fetch_all.phpt
ext/mysqli/tests/mysqli_fetch_all_oo.phpt
ext/mysqlnd/mysqlnd.h
ext/mysqlnd/mysqlnd_result.c
ext/mysqlnd/mysqlnd_structs.h

diff --git a/NEWS b/NEWS
index 73f97611bc6c1b53d60976304d1fb15b90095ab9..32712a85ca1b17c4dc94f7659651c50fad412367 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,9 @@ PHP                                                                        NEWS
 - hash:
   . Implemented FR #68109 (Add MurmurHash V3). (Anatol, Michael)
 
+- MySQLi:
+  . Fixed bug #70372 (Emulate mysqli_fetch_all() for libmysqlclient). (Nikita)
+
 - OpenSSL:
   . Bump minimal OpenSSL version to 1.0.2. (Jakub Zelenka)
 
index d2aaa08ac5dd8d47d8e72dee1b5f164b07a95bd9..6cccf69bf0397d5829039ec82e5d9ebb7ec09464 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -96,6 +96,10 @@ PHP 8.1 UPGRADE NOTES
 9. Other Changes to Extensions
 ========================================
 
+- MySQLi:
+  . The mysqli_stmt::next_result() and mysqli::fetch_all() methods are now
+    available when linking against libmysqlclient.
+
 - OpenSSL:
   . The OpenSSL extension now requires at least OpenSSL version 1.0.2.
 
index e4da55cbb4d39a110e078061c34cb1437ebf345f..07eead6a0f47da11311bf14535eb8fad9d176e04 100644 (file)
@@ -340,13 +340,11 @@ class mysqli_result implements IteratorAggregate
      */
     public function fetch_field_direct(int $index) {}
 
-#if defined(MYSQLI_USE_MYSQLND)
     /**
      * @return array|false
      * @alias mysqli_fetch_all
      */
     public function fetch_all(int $mode = MYSQLI_NUM) {}
-#endif
 
     /**
      * @return array|null|false
@@ -573,9 +571,7 @@ function mysqli_fetch_field_direct(mysqli_result $result, int $index): object|fa
 
 function mysqli_fetch_lengths(mysqli_result $result): array|false {}
 
-#if defined(MYSQLI_USE_MYSQLND)
 function mysqli_fetch_all(mysqli_result $result, int $mode = MYSQLI_NUM): array|false {}
-#endif
 
 function mysqli_fetch_array(mysqli_result $result, int $mode = MYSQLI_BOTH): array|null|false {}
 
index c7d4cac03a36db628ad1fecaccf5b7187ad0b626..f3dd5ae16ed56cc8a9684bacef21df1876ac5510 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 6af7fe4ad33232a118fdde74d13e0fb8a04fb4b0 */
+ * Stub hash: 8cd300f5106294e193fa85adc9c8a18a68d7d322 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
        ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
@@ -96,12 +96,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_lengths, 0, 1, MAY_
        ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
 ZEND_END_ARG_INFO()
 
-#if defined(MYSQLI_USE_MYSQLND)
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_all, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_NUM")
 ZEND_END_ARG_INFO()
-#endif
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_array, 0, 1, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
@@ -598,11 +596,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_result_fetch_field_direct, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-#if defined(MYSQLI_USE_MYSQLND)
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_result_fetch_all, 0, 0, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_NUM")
 ZEND_END_ARG_INFO()
-#endif
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_result_fetch_array, 0, 0, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_BOTH")
@@ -710,9 +706,7 @@ ZEND_FUNCTION(mysqli_fetch_field);
 ZEND_FUNCTION(mysqli_fetch_fields);
 ZEND_FUNCTION(mysqli_fetch_field_direct);
 ZEND_FUNCTION(mysqli_fetch_lengths);
-#if defined(MYSQLI_USE_MYSQLND)
 ZEND_FUNCTION(mysqli_fetch_all);
-#endif
 ZEND_FUNCTION(mysqli_fetch_array);
 ZEND_FUNCTION(mysqli_fetch_assoc);
 ZEND_FUNCTION(mysqli_fetch_object);
@@ -836,9 +830,7 @@ static const zend_function_entry ext_functions[] = {
        ZEND_FE(mysqli_fetch_fields, arginfo_mysqli_fetch_fields)
        ZEND_FE(mysqli_fetch_field_direct, arginfo_mysqli_fetch_field_direct)
        ZEND_FE(mysqli_fetch_lengths, arginfo_mysqli_fetch_lengths)
-#if defined(MYSQLI_USE_MYSQLND)
        ZEND_FE(mysqli_fetch_all, arginfo_mysqli_fetch_all)
-#endif
        ZEND_FE(mysqli_fetch_array, arginfo_mysqli_fetch_array)
        ZEND_FE(mysqli_fetch_assoc, arginfo_mysqli_fetch_assoc)
        ZEND_FE(mysqli_fetch_object, arginfo_mysqli_fetch_object)
@@ -1003,9 +995,7 @@ static const zend_function_entry class_mysqli_result_methods[] = {
        ZEND_ME_MAPPING(fetch_field, mysqli_fetch_field, arginfo_class_mysqli_result_fetch_field, ZEND_ACC_PUBLIC)
        ZEND_ME_MAPPING(fetch_fields, mysqli_fetch_fields, arginfo_class_mysqli_result_fetch_fields, ZEND_ACC_PUBLIC)
        ZEND_ME_MAPPING(fetch_field_direct, mysqli_fetch_field_direct, arginfo_class_mysqli_result_fetch_field_direct, ZEND_ACC_PUBLIC)
-#if defined(MYSQLI_USE_MYSQLND)
        ZEND_ME_MAPPING(fetch_all, mysqli_fetch_all, arginfo_class_mysqli_result_fetch_all, ZEND_ACC_PUBLIC)
-#endif
        ZEND_ME_MAPPING(fetch_array, mysqli_fetch_array, arginfo_class_mysqli_result_fetch_array, ZEND_ACC_PUBLIC)
        ZEND_ME_MAPPING(fetch_assoc, mysqli_fetch_assoc, arginfo_class_mysqli_result_fetch_assoc, ZEND_ACC_PUBLIC)
        ZEND_ME_MAPPING(fetch_object, mysqli_fetch_object, arginfo_class_mysqli_result_fetch_object, ZEND_ACC_PUBLIC)
index 6ea09b1fc2d7961470a9fdafeb3c0e6006f145c1..30b197d10dc95cd1db3140e7ddcf014519599b9b 100644 (file)
@@ -431,28 +431,39 @@ PHP_FUNCTION(mysqli_fetch_assoc)
 /* }}} */
 
 /* {{{ Fetches all result rows as an associative array, a numeric array, or both */
-#ifdef MYSQLI_USE_MYSQLND
 PHP_FUNCTION(mysqli_fetch_all)
 {
        MYSQL_RES       *result;
        zval            *mysql_result;
-       zend_long               mode = MYSQLND_FETCH_NUM;
+       zend_long               mode = MYSQLI_NUM;
 
        if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) {
                RETURN_THROWS();
        }
        MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
 
-       if (!mode || (mode & ~MYSQLND_FETCH_BOTH)) {
+       if (!mode || (mode & ~MYSQLI_BOTH)) {
                zend_argument_value_error(ERROR_ARG_POS(2), "must be one of MYSQLI_FETCH_NUM, "
                                 "MYSQLI_FETCH_ASSOC, or MYSQLI_FETCH_BOTH");
                RETURN_THROWS();
        }
 
-       mysqlnd_fetch_all(result, mode, return_value);
+       array_init_size(return_value, mysql_num_rows(result));
+
+       zend_ulong i = 0;
+       do {
+               zval row;
+               php_mysqli_fetch_into_hash_aux(&row, result, mode);
+               if (Z_TYPE(row) != IS_ARRAY) {
+                       zval_ptr_dtor_nogc(&row);
+                       break;
+               }
+               add_index_zval(return_value, i++, &row);
+       } while (1);
 }
 /* }}} */
 
+#ifdef MYSQLI_USE_MYSQLND
 /* {{{ Returns statistics about the zval cache */
 PHP_FUNCTION(mysqli_get_client_stats)
 {
index 1bc325e29f29fee9e5cef53075e3ae455f0cf14f..3e295d83bf673a8d69a3e359a4e4894c8cdea154 100644 (file)
@@ -3,7 +3,6 @@ Bug #75434 Wrong reflection for mysqli_fetch_all function
 --SKIPIF--
 <?php
 require_once('skipif.inc');
-if (!stristr(mysqli_get_client_info(), 'mysqlnd')) die("skip: only available in mysqlnd");
 ?>
 --FILE--
 <?php
index 629697a50c5216310ecc52238e5a79aa32a193a9..4837a5f6959e0c4b35783611871123ddbe3d225a 100644 (file)
@@ -27,6 +27,7 @@ require_once('skipifconnectfailure.inc');
         '__construct'           => true,
         'close'                 => true,
         'data_seek'             => true,
+        'fetch_all'             => true,
         'fetch_array'           => true,
         'fetch_assoc'           => true,
         'fetch_field'           => true,
@@ -39,8 +40,6 @@ require_once('skipifconnectfailure.inc');
         'free_result'           => true,
         'getIterator'           => true,
     );
-    if ($IS_MYSQLND)
-        $expected_methods['fetch_all'] = true;
 
     foreach ($methods as $k => $method) {
         if (isset($expected_methods[$method])) {
index ae99c2ca875712b63c303bd5f948f3e92e6fac83..fac34e3d88381237642779f8a84711a6a50e1d73 100644 (file)
@@ -4,8 +4,6 @@ mysqli_fetch_all()
 <?php
 require_once('skipif.inc');
 require_once('skipifconnectfailure.inc');
-if (!function_exists('mysqli_fetch_all'))
-    die("skip: function only available with mysqlnd");
 ?>
 --FILE--
 <?php
index df522f2eeb58012e0e81e36a74cc1fcdfa8d83f3..ebdc55443c6474d58ed2db6d046d455f2dcab8dd 100644 (file)
@@ -4,9 +4,6 @@ $mysqli->fetch_all() (introduced with mysqlnd)
 <?php
 require_once('skipif.inc');
 require_once('skipifconnectfailure.inc');
-
-if (!function_exists('mysqli_fetch_all'))
-    die("skip: function only available with mysqlnd");
 ?>
 --FILE--
 <?php
index d7bc2e3ccc41aa2af781578c5b37d6f4bacd153a..e8db599b9dcc9842fd4be8b68eca0f688ee56a4e 100644 (file)
@@ -102,7 +102,6 @@ PHPAPI void mysqlnd_debug(const char *mode);
 #define mysqlnd_fetch_row_c(result)                                            (result)->m.fetch_row_c((result))
 #define mysqlnd_fetch_row_zval(result, row_ptr, fetched) \
        (result)->m.fetch_row((result), (row_ptr), 0, (fetched))
-#define mysqlnd_fetch_all(result, flags, return_value) (result)->m.fetch_all((result), (flags), (return_value) ZEND_FILE_LINE_CC)
 #define mysqlnd_get_connection_stats(conn, values)             ((conn)->data)->m->get_statistics((conn)->data,  (values) ZEND_FILE_LINE_CC)
 #define mysqlnd_get_client_stats(values)                               _mysqlnd_get_client_stats(mysqlnd_global_stats, (values) ZEND_FILE_LINE_CC)
 
index 620f20599803a30567b4c25add767592e18113da..f7b69749d22c1ee89c750c432e6c5c91c7db4110 100644 (file)
@@ -1050,49 +1050,12 @@ MYSQLND_METHOD(mysqlnd_res, fetch_row_c)(MYSQLND_RES * result)
 /* }}} */
 
 
-/* {{{ mysqlnd_res::fetch_all */
-static void
-MYSQLND_METHOD(mysqlnd_res, fetch_all)(MYSQLND_RES * result, const unsigned int flags, zval *return_value ZEND_FILE_LINE_DC)
-{
-       zval  row;
-       zend_ulong i = 0;
-       MYSQLND_RES_BUFFERED *set = result->stored_data;
-
-       DBG_ENTER("mysqlnd_res::fetch_all");
-
-       if ((!result->unbuf && !set)) {
-               php_error_docref(NULL, E_WARNING, "fetch_all can be used only with buffered sets");
-               if (result->conn) {
-                       SET_CLIENT_ERROR(result->conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "fetch_all can be used only with buffered sets");
-               }
-               RETVAL_NULL();
-               DBG_VOID_RETURN;
-       }
-
-       /* 4 is a magic value. The cast is safe, if larger then the array will be later extended - no big deal :) */
-       array_init_size(return_value, set? (unsigned int) set->row_count : 4);
-
-       do {
-               mysqlnd_fetch_into(result, flags, &row);
-               if (Z_TYPE(row) != IS_ARRAY) {
-                       zval_ptr_dtor_nogc(&row);
-                       break;
-               }
-               add_index_zval(return_value, i++, &row);
-       } while (1);
-
-       DBG_VOID_RETURN;
-}
-/* }}} */
-
-
 MYSQLND_CLASS_METHODS_START(mysqlnd_res)
        MYSQLND_METHOD(mysqlnd_res, fetch_row),
        MYSQLND_METHOD(mysqlnd_res, use_result),
        MYSQLND_METHOD(mysqlnd_res, store_result),
        MYSQLND_METHOD(mysqlnd_res, fetch_into),
        MYSQLND_METHOD(mysqlnd_res, fetch_row_c),
-       MYSQLND_METHOD(mysqlnd_res, fetch_all),
        MYSQLND_METHOD(mysqlnd_res, num_rows),
        MYSQLND_METHOD(mysqlnd_res, num_fields),
        MYSQLND_METHOD(mysqlnd_res, skip_result),
index 47c8e491ec08dce1109d91f5b5be5e81a3399d6f..af2cafc576a8606b31144cd973eaed79481cdb68 100644 (file)
@@ -640,7 +640,6 @@ typedef MYSQLND_RES *               (*func_mysqlnd_res__use_result)(MYSQLND_RES * const resul
 typedef MYSQLND_RES *          (*func_mysqlnd_res__store_result)(MYSQLND_RES * result, MYSQLND_CONN_DATA * const conn, MYSQLND_STMT_DATA *stmt);
 typedef void                           (*func_mysqlnd_res__fetch_into)(MYSQLND_RES *result, const unsigned int flags, zval *return_value ZEND_FILE_LINE_DC);
 typedef MYSQLND_ROW_C          (*func_mysqlnd_res__fetch_row_c)(MYSQLND_RES *result);
-typedef void                           (*func_mysqlnd_res__fetch_all)(MYSQLND_RES *result, const unsigned int flags, zval *return_value ZEND_FILE_LINE_DC);
 typedef uint64_t                       (*func_mysqlnd_res__num_rows)(const MYSQLND_RES * const result);
 typedef unsigned int           (*func_mysqlnd_res__num_fields)(const MYSQLND_RES * const result);
 typedef enum_func_status       (*func_mysqlnd_res__skip_result)(MYSQLND_RES * const result);
@@ -671,7 +670,6 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_res)
        func_mysqlnd_res__store_result store_result;
        func_mysqlnd_res__fetch_into fetch_into;
        func_mysqlnd_res__fetch_row_c fetch_row_c;
-       func_mysqlnd_res__fetch_all fetch_all;
        func_mysqlnd_res__num_rows num_rows;
        func_mysqlnd_res__num_fields num_fields;
        func_mysqlnd_res__skip_result skip_result;