From 037512cfce6048aae3d3900abb12310e66bc97a5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 18 Dec 2020 12:13:17 +0100 Subject: Move fetch_all implementation out of mysqlnd 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. --- NEWS | 3 ++ UPGRADING | 4 +++ ext/mysqli/mysqli.stub.php | 4 --- ext/mysqli/mysqli_arginfo.h | 12 +------ ext/mysqli/mysqli_nonapi.c | 19 ++++++++--- ext/mysqli/tests/bug75434.phpt | 1 - .../mysqli_class_mysqli_result_interface.phpt | 3 +- ext/mysqli/tests/mysqli_fetch_all.phpt | 2 -- ext/mysqli/tests/mysqli_fetch_all_oo.phpt | 3 -- ext/mysqlnd/mysqlnd.h | 1 - ext/mysqlnd/mysqlnd_result.c | 37 ---------------------- ext/mysqlnd/mysqlnd_structs.h | 2 -- 12 files changed, 24 insertions(+), 67 deletions(-) diff --git a/NEWS b/NEWS index 73f97611bc..32712a85ca 100644 --- 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) diff --git a/UPGRADING b/UPGRADING index d2aaa08ac5..6cccf69bf0 100644 --- 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. diff --git a/ext/mysqli/mysqli.stub.php b/ext/mysqli/mysqli.stub.php index e4da55cbb4..07eead6a0f 100644 --- a/ext/mysqli/mysqli.stub.php +++ b/ext/mysqli/mysqli.stub.php @@ -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 {} diff --git a/ext/mysqli/mysqli_arginfo.h b/ext/mysqli/mysqli_arginfo.h index c7d4cac03a..f3dd5ae16e 100644 --- a/ext/mysqli/mysqli_arginfo.h +++ b/ext/mysqli/mysqli_arginfo.h @@ -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) diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 6ea09b1fc2..30b197d10d 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -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) { diff --git a/ext/mysqli/tests/bug75434.phpt b/ext/mysqli/tests/bug75434.phpt index 1bc325e29f..3e295d83bf 100644 --- a/ext/mysqli/tests/bug75434.phpt +++ b/ext/mysqli/tests/bug75434.phpt @@ -3,7 +3,6 @@ Bug #75434 Wrong reflection for mysqli_fetch_all function --SKIPIF-- --FILE-- 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])) { diff --git a/ext/mysqli/tests/mysqli_fetch_all.phpt b/ext/mysqli/tests/mysqli_fetch_all.phpt index ae99c2ca87..fac34e3d88 100644 --- a/ext/mysqli/tests/mysqli_fetch_all.phpt +++ b/ext/mysqli/tests/mysqli_fetch_all.phpt @@ -4,8 +4,6 @@ mysqli_fetch_all() --FILE-- fetch_all() (introduced with mysqlnd) --FILE-- 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) diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 620f205998..f7b69749d2 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -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), diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 47c8e491ec..af2cafc576 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -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; -- cgit v1.2.1