diff --git a/UPGRADING b/UPGRADING index 7f435880480d0..7f530497e7f5f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -25,6 +25,11 @@ PHP 8.1 UPGRADE NOTES result set and taking the maximum length. This is what PHP was doing internally previously. . The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect. + . The MYSQLI_STORE_RESULT_COPY_DATA option no longer has an effect. + +- MySQLnd: + . The mysqlnd.fetch_copy_data ini setting has been removed. However, this + should not result in user-visible behavior changes. - Standard: . version_compare() no longer accepts undocumented operator abbreviations. diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 405618896a014..0fc7017960256 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -1459,7 +1459,7 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_method) We create always persistent, as if the user want to connect to p:somehost, we can't convert the handle then */ - if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, TRUE))) + if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, TRUE))) #endif { efree(mysql); @@ -2527,11 +2527,7 @@ PHP_FUNCTION(mysqli_store_result) RETURN_THROWS(); } MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID); -#ifdef MYSQLI_USE_MYSQLND - result = flags & MYSQLI_STORE_RESULT_COPY_DATA? mysqlnd_store_result_ofs(mysql->mysql) : mysqlnd_store_result(mysql->mysql); -#else result = mysql_store_result(mysql->mysql); -#endif if (!result) { MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 364638c44a077..6ea09b1fc2d79 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -245,7 +245,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne #ifndef MYSQLI_USE_MYSQLND if (!(mysql->mysql = mysql_init(NULL))) { #else - if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent))) { + if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, persistent))) { #endif goto err; } @@ -307,7 +307,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne } } if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len, - port, socket, flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA) == NULL) + port, socket, flags, MYSQLND_CLIENT_NO_FLAG) == NULL) #endif { /* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */ @@ -689,12 +689,7 @@ PHP_FUNCTION(mysqli_query) switch (resultmode & ~MYSQLI_ASYNC) { #endif case MYSQLI_STORE_RESULT: -#ifdef MYSQLI_USE_MYSQLND - if (resultmode & MYSQLI_STORE_RESULT_COPY_DATA) { - result = mysqlnd_store_result_ofs(mysql->mysql); - } else -#endif - result = mysql_store_result(mysql->mysql); + result = mysql_store_result(mysql->mysql); break; case MYSQLI_USE_RESULT: result = mysql_use_result(mysql->mysql); diff --git a/ext/mysqli/mysqli_warning.c b/ext/mysqli/mysqli_warning.c index 6dd7090911e51..30af6cb960d1b 100644 --- a/ext/mysqli/mysqli_warning.c +++ b/ext/mysqli/mysqli_warning.c @@ -125,7 +125,7 @@ MYSQLI_WARNING * php_get_warnings(MYSQLND_CONN_DATA * mysql) return NULL; } - result = mysql->m->use_result(mysql, 0); + result = mysql->m->use_result(mysql); for (;;) { zval *entry; diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index b4d3d1f8c3327..582d8f152b832 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -112,9 +112,8 @@ PHPAPI void mysqlnd_debug(const char *mode); PHPAPI enum_func_status mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num); -#define mysqlnd_use_result(conn) ((conn)->data)->m->use_result((conn)->data, 0) -#define mysqlnd_store_result(conn) ((conn)->data)->m->store_result((conn)->data, MYSQLND_STORE_NO_COPY) -#define mysqlnd_store_result_ofs(conn) ((conn)->data)->m->store_result((conn)->data, MYSQLND_STORE_COPY) +#define mysqlnd_use_result(conn) ((conn)->data)->m->use_result((conn)->data) +#define mysqlnd_store_result(conn) ((conn)->data)->m->store_result((conn)->data) #define mysqlnd_next_result(conn) ((conn)->data)->m->next_result((conn)->data) #define mysqlnd_more_results(conn) ((conn)->data)->m->more_results((conn)->data) #define mysqlnd_free_result(r,e_or_i) ((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)), (e_or_i)) @@ -311,7 +310,6 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqlnd) zend_long debug_calloc_fail_threshold; zend_long debug_realloc_fail_threshold; char * sha256_server_public_key; - zend_bool fetch_data_copy; zend_bool collect_statistics; zend_bool collect_memory_statistics; ZEND_END_MODULE_GLOBALS(mysqlnd) diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 21eb7e703be5d..4d25488ee6c2b 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -456,7 +456,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, execute_init_commands)(MYSQLND_CONN_DATA * con } do { if (conn->last_query_type == QUERY_SELECT) { - MYSQLND_RES * result = conn->m->use_result(conn, 0); + MYSQLND_RES * result = conn->m->use_result(conn); if (result) { result->m.free_result(result, TRUE); } @@ -928,7 +928,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, list_method)(MYSQLND_CONN_DATA * conn, const c } if (PASS == conn->m->query(conn, show_query, show_query_len)) { - result = conn->m->store_result(conn, MYSQLND_STORE_NO_COPY); + result = conn->m->store_result(conn); } if (show_query != query) { mnd_sprintf_free(show_query); @@ -1810,7 +1810,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)(MYSQLND_CONN_DATA * cons /* {{{ mysqlnd_conn_data::use_result */ static MYSQLND_RES * -MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags) +MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn) { const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), use_result); MYSQLND_RES * result = NULL; @@ -1852,7 +1852,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn, co /* {{{ mysqlnd_conn_data::store_result */ static MYSQLND_RES * -MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags) +MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn) { const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), store_result); MYSQLND_RES * result = NULL; @@ -1862,7 +1862,6 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn, if (PASS == conn->m->local_tx_start(conn, this_func)) { do { - unsigned int f = flags; if (!conn->current_result) { break; } @@ -1875,25 +1874,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn, } MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS); - - /* overwrite */ - if ((conn->m->get_client_api_capabilities(conn) & MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA)) { - if (MYSQLND_G(fetch_data_copy)) { - f &= ~MYSQLND_STORE_NO_COPY; - f |= MYSQLND_STORE_COPY; - } - } else { - /* if for some reason PDO borks something */ - if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) { - f |= MYSQLND_STORE_COPY; - } - } - if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) { - SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Unknown fetch mode"); - DBG_ERR("Unknown fetch mode"); - break; - } - result = conn->current_result->m.store_result(conn->current_result, conn, f); + result = conn->current_result->m.store_result(conn->current_result, conn, NULL); if (!result) { conn->current_result->m.free_result(conn->current_result, TRUE); } diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index 191b8388b3469..6d6cefbb46624 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -686,18 +686,6 @@ enum php_mysqlnd_server_command #define MYSQLND_REFRESH_BACKUP_LOG 0x200000L -#define MYSQLND_STORE_PS 1 -#define MYSQLND_STORE_NO_COPY 2 -#define MYSQLND_STORE_COPY 4 - -enum mysqlnd_buffered_type -{ - MYSQLND_BUFFERED_TYPE_ZVAL = 1, - MYSQLND_BUFFERED_TYPE_C -}; - - #define MYSQLND_CLIENT_NO_FLAG 0 -#define MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA 1 #endif /* MYSQLND_ENUM_N_DEF_H */ diff --git a/ext/mysqlnd/mysqlnd_ext_plugin.c b/ext/mysqlnd/mysqlnd_ext_plugin.c index 58a4ee767ecc6..cf28b81ea585c 100644 --- a/ext/mysqlnd/mysqlnd_ext_plugin.c +++ b/ext/mysqlnd/mysqlnd_ext_plugin.c @@ -83,30 +83,16 @@ mysqlnd_plugin__get_plugin_result_unbuffered_data(const MYSQLND_RES_UNBUFFERED * } /* }}} */ - -/* {{{ _mysqlnd_plugin__get_plugin_result_buffered_data */ -static void ** -mysqlnd_plugin__get_plugin_result_buffered_data_zval(const MYSQLND_RES_BUFFERED_ZVAL * result, const unsigned int plugin_id) -{ - DBG_ENTER("_mysqlnd_plugin__get_plugin_result_data"); - DBG_INF_FMT("plugin_id=%u", plugin_id); - if (!result || plugin_id >= mysqlnd_plugin_count()) { - return NULL; - } - DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_ZVAL) + plugin_id * sizeof(void *))); -} -/* }}} */ - /* {{{ mysqlnd_plugin__get_plugin_result_buffered_data */ static void ** -mysqlnd_plugin__get_plugin_result_buffered_data_c(const MYSQLND_RES_BUFFERED_C * result, const unsigned int plugin_id) +mysqlnd_plugin__get_plugin_result_buffered_data(const MYSQLND_RES_BUFFERED * result, const unsigned int plugin_id) { DBG_ENTER("mysqlnd_plugin__get_plugin_result_data"); DBG_INF_FMT("plugin_id=%u", plugin_id); if (!result || plugin_id >= mysqlnd_plugin_count()) { return NULL; } - DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_C) + plugin_id * sizeof(void *))); + DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED) + plugin_id * sizeof(void *))); } /* }}} */ @@ -172,8 +158,7 @@ struct st_mysqlnd_plugin__plugin_area_getters mysqlnd_plugin_area_getters = mysqlnd_plugin__get_plugin_connection_data_data, mysqlnd_plugin__get_plugin_result_data, mysqlnd_plugin__get_plugin_result_unbuffered_data, - mysqlnd_plugin__get_plugin_result_buffered_data_zval, - mysqlnd_plugin__get_plugin_result_buffered_data_c, + mysqlnd_plugin__get_plugin_result_buffered_data, mysqlnd_plugin__get_plugin_stmt_data, mysqlnd_plugin__get_plugin_protocol_data, mysqlnd_plugin__get_plugin_pfc_data, diff --git a/ext/mysqlnd/mysqlnd_ext_plugin.h b/ext/mysqlnd/mysqlnd_ext_plugin.h index 713eb1f44f3b5..027fda976aa25 100644 --- a/ext/mysqlnd/mysqlnd_ext_plugin.h +++ b/ext/mysqlnd/mysqlnd_ext_plugin.h @@ -25,8 +25,7 @@ struct st_mysqlnd_plugin__plugin_area_getters void ** (*get_connection_data_area)(const MYSQLND_CONN_DATA * conn, const unsigned int plugin_id); void ** (*get_result_area)(const MYSQLND_RES * result, const unsigned int plugin_id); void ** (*get_unbuffered_area)(const MYSQLND_RES_UNBUFFERED * result, const unsigned int plugin_id); - void ** (*get_result_buffered_area)(const MYSQLND_RES_BUFFERED_ZVAL * result, const unsigned int plugin_id); - void ** (*get_result_buffered_aread_c)(const MYSQLND_RES_BUFFERED_C * result, const unsigned int plugin_id); + void ** (*get_result_buffered_aread)(const MYSQLND_RES_BUFFERED * result, const unsigned int plugin_id); void ** (*get_stmt_area)(const MYSQLND_STMT * stmt, const unsigned int plugin_id); void ** (*get_protocol_decoder_area)(const MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * factory, const unsigned int plugin_id); void ** (*get_pfc_area)(const MYSQLND_PFC * pfc, const unsigned int plugin_id); @@ -39,8 +38,7 @@ PHPAPI extern struct st_mysqlnd_plugin__plugin_area_getters mysqlnd_plugin_area_ #define mysqlnd_plugin_get_plugin_connection_data_data(c, p_id) mysqlnd_plugin_area_getters.get_connection_data_area((c), (p_id)) #define mysqlnd_plugin_get_plugin_result_data(res, p_id) mysqlnd_plugin_area_getters.get_result_area((res), (p_id)) #define mysqlnd_plugin_get_plugin_result_unbuffered_data(res, p_id) mysqlnd_plugin_area_getters.get_unbuffered_area((res), (p_id)) -#define mysqlnd_plugin_get_plugin_result_buffered_data_zval(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_area((res), (p_id)) -#define mysqlnd_plugin_get_plugin_result_buffered_data_c(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_aread_c((res), (p_id)) +#define mysqlnd_plugin_get_plugin_result_buffered_data_c(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_aread((res), (p_id)) #define mysqlnd_plugin_get_plugin_stmt_data(stmt, p_id) mysqlnd_plugin_area_getters.get_stmt_area((stmt), (p_id)) #define mysqlnd_plugin_get_plugin_protocol_data(proto, p_id) mysqlnd_plugin_area_getters.get_protocol_decoder_area((proto), (p_id)) #define mysqlnd_plugin_get_plugin_pfc_data(pfc, p_id) mysqlnd_plugin_area_getters.get_pfc_area((pfc), (p_id)) diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index ccafa26675e20..7811f51832054 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -79,7 +79,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s) result->type = MYSQLND_RES_PS_BUF; /* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */ - result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result, result->field_count, TRUE); + result->stored_data = mysqlnd_result_buffered_init(result, result->field_count, stmt); if (!result->stored_data) { SET_OOM_ERROR(conn->error_info); DBG_RETURN(NULL); @@ -87,30 +87,8 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s) ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE); - result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; - if (PASS == ret) { - if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; - if (result->stored_data->row_count) { - /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ - if (result->stored_data->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) { - SET_OOM_ERROR(conn->error_info); - DBG_RETURN(NULL); - } - /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */ - set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval))); - if (!set->data) { - SET_OOM_ERROR(conn->error_info); - DBG_RETURN(NULL); - } - memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval))); - } - /* Position at the first row */ - set->data_cursor = set->data; - } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) { - /*TODO*/ - } + result->stored_data->current_row = 0; /* libmysql API docs say it should be so for SELECT statements */ UPSERT_STATUS_SET_AFFECTED_ROWS(stmt->upsert_status, stmt->result->stored_data->row_count); @@ -183,7 +161,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s) break; } - if (result->m.store_result(result, conn, MYSQLND_STORE_PS | MYSQLND_STORE_NO_COPY)) { + if (result->m.store_result(result, conn, stmt)) { UPSERT_STATUS_SET_AFFECTED_ROWS(stmt->upsert_status, result->stored_data->row_count); stmt->state = MYSQLND_STMT_PREPARED; result->type = MYSQLND_RES_PS_BUF; @@ -563,11 +541,6 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s, enum_mysqlnd_parse_e } stmt->field_count = stmt->result->field_count = conn->field_count; - if (stmt->result->stored_data) { - stmt->result->stored_data->lengths = NULL; - } else if (stmt->result->unbuf) { - stmt->result->unbuf->lengths = NULL; - } if (stmt->field_count) { stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE; /* @@ -731,191 +704,6 @@ MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, const enum_my /* }}} */ -/* {{{ mysqlnd_stmt_fetch_row_buffered */ -enum_func_status -mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything) -{ - MYSQLND_STMT * s = (MYSQLND_STMT *) param; - MYSQLND_STMT_DATA * stmt = s? s->data : NULL; - const MYSQLND_RES_METADATA * const meta = result->meta; - unsigned int field_count = meta->field_count; - - DBG_ENTER("mysqlnd_stmt_fetch_row_buffered"); - *fetched_anything = FALSE; - DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L); - - /* If we haven't read everything */ - if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; - if (set->data_cursor && - (set->data_cursor - set->data) < (result->stored_data->row_count * field_count)) - { - /* The user could have skipped binding - don't crash*/ - if (stmt->result_bind) { - unsigned int i; - zval *current_row = set->data_cursor; - - if (Z_ISUNDEF(current_row[0])) { - uint64_t row_num = (set->data_cursor - set->data) / field_count; - enum_func_status rc = result->stored_data->m.row_decoder(&result->stored_data->row_buffers[row_num], - current_row, - meta->field_count, - meta->fields, - result->conn->options->int_and_float_native, - result->conn->stats); - if (PASS != rc) { - DBG_RETURN(FAIL); - } - } - - for (i = 0; i < result->field_count; i++) { - /* copy the type */ - zval *resultzv = &stmt->result_bind[i].zv; - if (stmt->result_bind[i].bound == TRUE) { - DBG_INF_FMT("i=%u type=%u", i, Z_TYPE(current_row[i])); - ZEND_TRY_ASSIGN_COPY_EX(resultzv, ¤t_row[i], 0); - } - } - } - set->data_cursor += field_count; - *fetched_anything = TRUE; - /* buffered result sets don't have a connection */ - MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF); - DBG_INF("row fetched"); - } else { - set->data_cursor = NULL; - DBG_INF("no more data"); - } - } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) { - /*TODO*/ - } - DBG_INF("PASS"); - DBG_RETURN(PASS); -} -/* }}} */ - - -/* {{{ mysqlnd_stmt_fetch_row_unbuffered */ -enum_func_status -mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything) -{ - enum_func_status ret; - MYSQLND_STMT * s = (MYSQLND_STMT *) param; - MYSQLND_STMT_DATA * stmt = s? s->data : NULL; - MYSQLND_PACKET_ROW * row_packet; - MYSQLND_CONN_DATA * conn = result->conn; - void *checkpoint; - - DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered"); - - *fetched_anything = FALSE; - - if (result->unbuf->eof_reached) { - /* No more rows obviously */ - DBG_INF("EOF already reached"); - DBG_RETURN(PASS); - } - if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) { - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); - DBG_ERR("command out of sync"); - DBG_RETURN(FAIL); - } - if (!(row_packet = result->unbuf->row_packet)) { - DBG_RETURN(FAIL); - } - - checkpoint = result->memory_pool->checkpoint; - mysqlnd_mempool_save_state(result->memory_pool); - - /* - If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to - result->unbuf->m.free_last_data() before it. The function returns always true. - */ - if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) { - unsigned int i, field_count = result->field_count; - - if (stmt && stmt->result_bind) { - result->unbuf->m.free_last_data(result->unbuf, conn->stats); - - result->unbuf->last_row_buffer = row_packet->row_buffer; - row_packet->row_buffer.ptr = NULL; - - if (PASS != result->unbuf->m.row_decoder(&result->unbuf->last_row_buffer, - result->unbuf->last_row_data, - row_packet->field_count, - row_packet->fields_metadata, - conn->options->int_and_float_native, - conn->stats)) - { - mysqlnd_mempool_restore_state(result->memory_pool); - result->memory_pool->checkpoint = checkpoint; - DBG_RETURN(FAIL); - } - - for (i = 0; i < field_count; i++) { - zval *resultzv = &stmt->result_bind[i].zv; - if (stmt->result_bind[i].bound == TRUE) { - zval *data = &result->unbuf->last_row_data[i]; - ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0); - /* copied data, thus also the ownership. Thus null data */ - ZVAL_NULL(data); - } - } - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF); - } else { - DBG_INF("skipping extraction"); - /* - Data has been allocated and usually result->unbuf->m.free_last_data() - frees it but we can't call this function as it will cause problems with - the bound variables. Thus we need to do part of what it does or Zend will - report leaks. - */ - row_packet->result_set_memory_pool->free_chunk( - row_packet->result_set_memory_pool, row_packet->row_buffer.ptr); - row_packet->row_buffer.ptr = NULL; - } - - result->unbuf->row_count++; - *fetched_anything = TRUE; - } else if (ret == FAIL) { - if (row_packet->error_info.error_no) { - COPY_CLIENT_ERROR(conn->error_info, row_packet->error_info); - if (stmt) { - COPY_CLIENT_ERROR(stmt->error_info, row_packet->error_info); - } - } - if (GET_CONNECTION_STATE(&conn->state) != CONN_QUIT_SENT) { - SET_CONNECTION_STATE(&conn->state, CONN_READY); - } - result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ - } else if (row_packet->eof) { - DBG_INF("EOF"); - /* Mark the connection as usable again */ - result->unbuf->eof_reached = TRUE; - UPSERT_STATUS_RESET(conn->upsert_status); - UPSERT_STATUS_SET_WARNINGS(conn->upsert_status, row_packet->warning_count); - UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, row_packet->server_status); - - /* - result->row_packet will be cleaned when - destroying the result object - */ - if (UPSERT_STATUS_GET_SERVER_STATUS(conn->upsert_status) & SERVER_MORE_RESULTS_EXISTS) { - SET_CONNECTION_STATE(&conn->state, CONN_NEXT_RESULT_PENDING); - } else { - SET_CONNECTION_STATE(&conn->state, CONN_READY); - } - } - - mysqlnd_mempool_restore_state(result->memory_pool); - result->memory_pool->checkpoint = checkpoint; - - DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything); - DBG_RETURN(ret); -} -/* }}} */ - - /* {{{ mysqlnd_stmt::use_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s) @@ -945,9 +733,10 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s) MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_UNBUFFERED_SETS); result = stmt->result; - result->m.use_result(stmt->result, TRUE); - result->unbuf->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor: - mysqlnd_stmt_fetch_row_unbuffered; + result->m.use_result(stmt->result, stmt); + if (stmt->cursor_exists) { + result->unbuf->m.fetch_row = mysqlnd_fetch_stmt_row_cursor; + } stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED; DBG_INF_FMT("%p", result); @@ -958,12 +747,11 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s) /* {{{ mysqlnd_fetch_row_cursor */ enum_func_status -mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything) +mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, zval **row_ptr, const unsigned int flags, zend_bool * fetched_anything) { enum_func_status ret; - MYSQLND_STMT * s = (MYSQLND_STMT *) param; - MYSQLND_STMT_DATA * stmt = s? s->data : NULL; - MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL; + MYSQLND_STMT_DATA * stmt = result->unbuf->stmt; + MYSQLND_CONN_DATA * conn = stmt->conn; zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */]; MYSQLND_PACKET_ROW * row_packet; @@ -1004,16 +792,13 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned UPSERT_STATUS_RESET(stmt->upsert_status); if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) { - unsigned int i, field_count = result->field_count; - - if (stmt->result_bind) { - result->unbuf->m.free_last_data(result->unbuf, conn->stats); - + if (row_ptr) { result->unbuf->last_row_buffer = row_packet->row_buffer; row_packet->row_buffer.ptr = NULL; + *row_ptr = result->row_data; if (PASS != result->unbuf->m.row_decoder(&result->unbuf->last_row_buffer, - result->unbuf->last_row_data, + result->row_data, row_packet->field_count, row_packet->fields_metadata, conn->options->int_and_float_native, @@ -1021,32 +806,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned { DBG_RETURN(FAIL); } - - /* If no result bind, do nothing. We consumed the data */ - for (i = 0; i < field_count; i++) { - zval *resultzv = &stmt->result_bind[i].zv; - if (stmt->result_bind[i].bound == TRUE) { - zval *data = &result->unbuf->last_row_data[i]; - - DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, &stmt->result_bind[i].zv, - Z_TYPE_P(data), Z_REFCOUNTED(stmt->result_bind[i].zv)? - Z_REFCOUNT(stmt->result_bind[i].zv) : 0); - - ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0); - /* copied data, thus also the ownership. Thus null data */ - ZVAL_NULL(data); - } - } } else { DBG_INF("skipping extraction"); - /* - Data has been allocated and usually result->unbuf->m.free_last_data() - frees it but we can't call this function as it will cause problems with - the bound variables. Thus we need to do part of what it does or Zend will - report leaks. - */ - row_packet->result_set_memory_pool->free_chunk( - row_packet->result_set_memory_pool, row_packet->row_buffer.ptr); row_packet->row_buffer.ptr = NULL; } /* We asked for one row, the next one should be EOF, eat it */ @@ -1081,6 +842,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned row_packet->server_status, row_packet->warning_count, result->unbuf->eof_reached); DBG_RETURN(ret); + return FAIL; } /* }}} */ @@ -1112,7 +874,24 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fe SET_EMPTY_ERROR(stmt->error_info); SET_EMPTY_ERROR(conn->error_info); - ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything); + if (stmt->result_bind) { + zval *row_data; + ret = stmt->result->m.fetch_row(stmt->result, &row_data, 0, fetched_anything); + if (ret == PASS && *fetched_anything) { + unsigned field_count = stmt->result->field_count; + for (unsigned i = 0; i < field_count; i++) { + zval *resultzv = &stmt->result_bind[i].zv; + if (stmt->result_bind[i].bound == TRUE) { + DBG_INF_FMT("i=%u type=%u", i, Z_TYPE(row_data[i])); + ZEND_TRY_ASSIGN_VALUE_EX(resultzv, &row_data[i], 0); + } else { + zval_ptr_dtor_nogc(&row_data[i]); + } + } + } + } else { + ret = stmt->result->m.fetch_row(stmt->result, NULL, 0, fetched_anything); + } DBG_RETURN(ret); } /* }}} */ @@ -1728,7 +1507,7 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s) break; } result_meta->type = MYSQLND_RES_NORMAL; - result_meta->unbuf = mysqlnd_result_unbuffered_init(result_meta, stmt->field_count, TRUE); + result_meta->unbuf = mysqlnd_result_unbuffered_init(result_meta, stmt->field_count, stmt); if (!result_meta->unbuf) { break; } diff --git a/ext/mysqlnd/mysqlnd_ps.h b/ext/mysqlnd/mysqlnd_ps.h index 0d4f7f80688b6..9e10fbab77bec 100644 --- a/ext/mysqlnd/mysqlnd_ps.h +++ b/ext/mysqlnd/mysqlnd_ps.h @@ -32,8 +32,8 @@ struct st_mysqlnd_perm_bind { extern struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1]; -enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything); -enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything); +enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, zval **row_data, const unsigned int flags, zend_bool * fetched_anything); +enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, zval **row_data, const unsigned int flags, zend_bool * fetched_anything); void _mysqlnd_init_ps_subsystem();/* This one is private, mysqlnd_library_init() will call it */ void _mysqlnd_init_ps_fetch_subsystem(); diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 05a04296e680a..620f20599803a 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -27,40 +27,11 @@ #include "mysqlnd_debug.h" #include "mysqlnd_ext_plugin.h" -/* {{{ mysqlnd_result_unbuffered::free_last_data */ -static void -MYSQLND_METHOD(mysqlnd_result_unbuffered, free_last_data)(MYSQLND_RES_UNBUFFERED * unbuf, MYSQLND_STATS * const global_stats) -{ - DBG_ENTER("mysqlnd_res::unbuffered_free_last_data"); - - if (!unbuf) { - DBG_VOID_RETURN; - } - - DBG_INF_FMT("field_count=%u", unbuf->field_count); - if (unbuf->last_row_buffer.ptr) { - DBG_INF("Freeing last row buffer"); - for (unsigned i = 0; i < unbuf->field_count; i++) { - zval_ptr_dtor_nogc(&unbuf->last_row_data[i]); - } - - /* Nothing points to this buffer now, free it */ - unbuf->result_set_memory_pool->free_chunk( - unbuf->result_set_memory_pool, unbuf->last_row_buffer.ptr); - unbuf->last_row_buffer.ptr = NULL; - } - - DBG_VOID_RETURN; -} -/* }}} */ - - /* {{{ mysqlnd_result_unbuffered::free_result */ static void MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED * const result, MYSQLND_STATS * const global_stats) { DBG_ENTER("mysqlnd_result_unbuffered, free_result"); - result->m.free_last_data(result, global_stats); /* must be free before because references the memory pool */ if (result->row_packet) { @@ -73,47 +44,15 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED * } /* }}} */ - -/* {{{ mysqlnd_result_buffered_zval::free_result */ -static void -MYSQLND_METHOD(mysqlnd_result_buffered_zval, free_result)(MYSQLND_RES_BUFFERED_ZVAL * const set) +static void mysqlnd_result_free_prev_data(MYSQLND_RES *result) { - zval * data = set->data; - - DBG_ENTER("mysqlnd_result_buffered_zval::free_result"); - - set->data = NULL; /* prevent double free if following loop is interrupted */ - if (data) { - const unsigned int field_count = set->field_count; - int64_t row; - - for (row = set->row_count - 1; row >= 0; row--) { - zval *current_row = data + row * field_count; - int64_t col; - - if (current_row != NULL) { - for (col = field_count - 1; col >= 0; --col) { - zval_ptr_dtor_nogc(&(current_row[col])); - } - } + if (result->free_row_data) { + for (unsigned i = 0; i < result->field_count; ++i) { + zval_ptr_dtor_nogc(&result->row_data[i]); } - mnd_efree(data); + result->free_row_data = 0; } - set->data_cursor = NULL; - DBG_VOID_RETURN; -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_c::free_result */ -static void -MYSQLND_METHOD(mysqlnd_result_buffered_c, free_result)(MYSQLND_RES_BUFFERED_C * const set) -{ - DBG_ENTER("mysqlnd_result_buffered_c::free_result"); - DBG_VOID_RETURN; } -/* }}} */ - /* {{{ mysqlnd_result_buffered::free_result */ static void @@ -125,12 +64,6 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons mysqlnd_error_info_free_contents(&set->error_info); - if (set->type == MYSQLND_BUFFERED_TYPE_ZVAL) { - MYSQLND_METHOD(mysqlnd_result_buffered_zval, free_result)((MYSQLND_RES_BUFFERED_ZVAL *) set); - } if (set->type == MYSQLND_BUFFERED_TYPE_C) { - MYSQLND_METHOD(mysqlnd_result_buffered_c, free_result)((MYSQLND_RES_BUFFERED_C *) set); - } - if (set->row_buffers) { mnd_efree(set->row_buffers); set->row_buffers = NULL; @@ -148,6 +81,8 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES * result) DBG_ENTER("mysqlnd_res::free_result_buffers"); DBG_INF_FMT("%s", result->unbuf? "unbuffered":(result->stored_data? "buffered":"unknown")); + mysqlnd_result_free_prev_data(result); + if (result->meta) { ZEND_ASSERT(zend_arena_contains(result->memory_pool->arena, result->meta)); result->meta->m->free_metadata(result->meta); @@ -429,44 +364,11 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) completeness. */ static const size_t * -MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_lengths)(const MYSQLND_RES_BUFFERED * const result) -{ - const MYSQLND_RES_BUFFERED_ZVAL * const set = (const MYSQLND_RES_BUFFERED_ZVAL *) result; - /* - If: - - unbuffered result - - first row has not been read - - last_row has been read - */ - DBG_ENTER("mysqlnd_result_buffered_zval::fetch_lengths"); - - if (set->data_cursor == NULL || - set->data_cursor == set->data || - ((set->data_cursor - set->data) > (result->row_count * result->field_count) )) - { - DBG_INF("EOF"); - DBG_RETURN(NULL);/* No rows or no more rows */ - } - DBG_INF("non NULL"); - DBG_RETURN(result->lengths); -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_c::fetch_lengths */ -/* - Do lazy initialization for buffered results. As PHP strings have - length inside, this function makes not much sense in the context - of PHP, to be called as separate function. But let's have it for - completeness. -*/ -static const size_t * -MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_lengths)(const MYSQLND_RES_BUFFERED * const result) +MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths)(const MYSQLND_RES_BUFFERED * const result) { - const MYSQLND_RES_BUFFERED_C * const set = (const MYSQLND_RES_BUFFERED_C *) result; - DBG_ENTER("mysqlnd_result_buffered_c::fetch_lengths"); + DBG_ENTER("mysqlnd_result_buffered::fetch_lengths"); - if (set->current_row > set->row_count || set->current_row == 0) { + if (result->current_row > result->row_count || result->current_row == 0) { DBG_INF("EOF"); DBG_RETURN(NULL); /* No more rows, or no fetched row */ } @@ -503,139 +405,21 @@ MYSQLND_METHOD(mysqlnd_res, fetch_lengths)(const MYSQLND_RES * const result) /* }}} */ -/* {{{ mysqlnd_result_unbuffered::fetch_row_c */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything) -{ - enum_func_status ret; - MYSQLND_ROW_C *row = (MYSQLND_ROW_C *) param; - MYSQLND_PACKET_ROW *row_packet = result->unbuf->row_packet; - MYSQLND_RES_METADATA * const meta = result->meta; - MYSQLND_CONN_DATA * const conn = result->conn; - void *checkpoint; - - DBG_ENTER("mysqlnd_result_unbuffered::fetch_row_c"); - - *fetched_anything = FALSE; - if (result->unbuf->eof_reached) { - /* No more rows obviously */ - DBG_RETURN(PASS); - } - if (!conn || GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) { - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); - DBG_RETURN(FAIL); - } - if (!row_packet) { - /* Not fully initialized object that is being cleaned up */ - DBG_RETURN(FAIL); - } - - checkpoint = result->memory_pool->checkpoint; - mysqlnd_mempool_save_state(result->memory_pool); - - /* - If we skip rows (row == NULL) we have to - result->m.unbuffered_free_last_data() before it. The function returns always true. - */ - if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) { - result->unbuf->m.free_last_data(result->unbuf, conn->stats); - - result->unbuf->last_row_buffer = row_packet->row_buffer; - row_packet->row_buffer.ptr = NULL; - - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF); - - unsigned int i, field_count = meta->field_count; - - enum_func_status rc = result->unbuf->m.row_decoder(&result->unbuf->last_row_buffer, - result->unbuf->last_row_data, - field_count, - row_packet->fields_metadata, - conn->options->int_and_float_native, - conn->stats); - if (PASS != rc) { - mysqlnd_mempool_restore_state(result->memory_pool); - result->memory_pool->checkpoint = checkpoint; - DBG_RETURN(FAIL); - } - { - *row = mnd_emalloc(field_count * sizeof(char *)); - MYSQLND_FIELD * field = meta->fields; - size_t * lengths = result->unbuf->lengths; - - for (i = 0; i < field_count; i++, field++) { - zval * data = &result->unbuf->last_row_data[i]; - const size_t len = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0; - -/* BEGIN difference between normal normal fetch and _c */ - if (Z_TYPE_P(data) != IS_NULL) { - convert_to_string(data); - (*row)[i] = Z_STRVAL_P(data); - } else { - (*row)[i] = NULL; - } -/* END difference between normal normal fetch and _c */ - - if (lengths) { - lengths[i] = len; - } - } - } - result->unbuf->row_count++; - *fetched_anything = TRUE; - } else if (ret == FAIL) { - if (row_packet->error_info.error_no) { - COPY_CLIENT_ERROR(conn->error_info, row_packet->error_info); - DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error); - } - if (GET_CONNECTION_STATE(&conn->state) != CONN_QUIT_SENT) { - SET_CONNECTION_STATE(&conn->state, CONN_READY); - } - result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ - } else if (row_packet->eof) { - /* Mark the connection as usable again */ - DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count, row_packet->server_status); - result->unbuf->eof_reached = TRUE; - - UPSERT_STATUS_RESET(conn->upsert_status); - UPSERT_STATUS_SET_WARNINGS(conn->upsert_status, row_packet->warning_count); - UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, row_packet->server_status); - /* - result->row_packet will be cleaned when - destroying the result object - */ - if (UPSERT_STATUS_GET_SERVER_STATUS(conn->upsert_status) & SERVER_MORE_RESULTS_EXISTS) { - SET_CONNECTION_STATE(&conn->state, CONN_NEXT_RESULT_PENDING); - } else { - SET_CONNECTION_STATE(&conn->state, CONN_READY); - } - result->unbuf->m.free_last_data(result->unbuf, conn->stats); - } - - mysqlnd_mempool_restore_state(result->memory_pool); - result->memory_pool->checkpoint = checkpoint; - - DBG_INF_FMT("ret=%s fetched=%u", ret == PASS? "PASS":"FAIL", *fetched_anything); - DBG_RETURN(PASS); -} -/* }}} */ - - /* {{{ mysqlnd_result_unbuffered::fetch_row */ static enum_func_status -MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything) +MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, zval **row_ptr, const unsigned int flags, zend_bool * fetched_anything) { - enum_func_status ret; - zval *row = (zval *) param; + enum_func_status ret; MYSQLND_PACKET_ROW *row_packet = result->unbuf->row_packet; const MYSQLND_RES_METADATA * const meta = result->meta; + MYSQLND_RES_UNBUFFERED *set = result->unbuf; MYSQLND_CONN_DATA * const conn = result->conn; void *checkpoint; DBG_ENTER("mysqlnd_result_unbuffered::fetch_row"); *fetched_anything = FALSE; - if (result->unbuf->eof_reached) { + if (set->eof_reached) { /* No more rows obviously */ DBG_RETURN(PASS); } @@ -651,83 +435,53 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void checkpoint = result->memory_pool->checkpoint; mysqlnd_mempool_save_state(result->memory_pool); - /* - If we skip rows (row == NULL) we have to - result->m.unbuffered_free_last_data() before it. The function returns always true. - */ if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) { - result->unbuf->m.free_last_data(result->unbuf, conn->stats); - - result->unbuf->last_row_buffer = row_packet->row_buffer; + set->last_row_buffer = row_packet->row_buffer; row_packet->row_buffer.ptr = NULL; - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF); + MYSQLND_INC_CONN_STATISTIC(conn->stats, set->stmt + ? STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF + : STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF); - if (row) { - unsigned int i, field_count = meta->field_count; + if (row_ptr) { + unsigned int field_count = meta->field_count; - enum_func_status rc = result->unbuf->m.row_decoder(&result->unbuf->last_row_buffer, - result->unbuf->last_row_data, - field_count, - row_packet->fields_metadata, - conn->options->int_and_float_native, - conn->stats); + *row_ptr = result->row_data; + enum_func_status rc = set->m.row_decoder( + &set->last_row_buffer, result->row_data, field_count, + row_packet->fields_metadata, conn->options->int_and_float_native, conn->stats); if (PASS != rc) { mysqlnd_mempool_restore_state(result->memory_pool); result->memory_pool->checkpoint = checkpoint; DBG_RETURN(FAIL); } - { - HashTable * row_ht = Z_ARRVAL_P(row); - MYSQLND_FIELD * field = meta->fields; - size_t * lengths = result->unbuf->lengths; - - for (i = 0; i < field_count; i++, field++) { - zval * data = &result->unbuf->last_row_data[i]; - const size_t len = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0; - - if (flags & MYSQLND_FETCH_NUM) { - if (zend_hash_index_add(row_ht, i, data) != NULL) { - Z_TRY_ADDREF_P(data); - } - } - if (flags & MYSQLND_FETCH_ASSOC) { - /* zend_hash_quick_update needs length + trailing zero */ - /* QQ: Error handling ? */ - /* - zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether - the index is a numeric and convert it to it. This however means constant - hashing of the column name, which is not needed as it can be precomputed. - */ - Z_TRY_ADDREF_P(data); - if (meta->fields[i].is_numeric == FALSE) { - zend_hash_update(row_ht, meta->fields[i].sname, data); - } else { - zend_hash_index_update(row_ht, meta->fields[i].num_key, data); - } - } - if (lengths) { - lengths[i] = len; - } + size_t *lengths = set->lengths; + if (lengths) { + for (unsigned i = 0; i < field_count; i++) { + zval *data = &result->row_data[i]; + lengths[i] = Z_TYPE_P(data) == IS_STRING ? Z_STRLEN_P(data) : 0; } } } - result->unbuf->row_count++; + set->row_count++; *fetched_anything = TRUE; } else if (ret == FAIL) { if (row_packet->error_info.error_no) { COPY_CLIENT_ERROR(conn->error_info, row_packet->error_info); + if (set->stmt) { + COPY_CLIENT_ERROR(set->stmt->error_info, row_packet->error_info); + } DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error); } if (GET_CONNECTION_STATE(&conn->state) != CONN_QUIT_SENT) { SET_CONNECTION_STATE(&conn->state, CONN_READY); } - result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ + set->eof_reached = TRUE; /* so next time we won't get an error */ } else if (row_packet->eof) { /* Mark the connection as usable again */ DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count, row_packet->server_status); - result->unbuf->eof_reached = TRUE; + set->eof_reached = TRUE; UPSERT_STATUS_RESET(conn->upsert_status); UPSERT_STATUS_SET_WARNINGS(conn->upsert_status, row_packet->warning_count); @@ -741,7 +495,6 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void } else { SET_CONNECTION_STATE(&conn->state, CONN_READY); } - result->unbuf->m.free_last_data(result->unbuf, conn->stats); } mysqlnd_mempool_restore_state(result->memory_pool); @@ -755,20 +508,20 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void /* {{{ mysqlnd_res::use_result */ static MYSQLND_RES * -MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, const zend_bool ps) +MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, MYSQLND_STMT_DATA *stmt) { MYSQLND_CONN_DATA * const conn = result->conn; DBG_ENTER("mysqlnd_res::use_result"); SET_EMPTY_ERROR(conn->error_info); - if (ps == FALSE) { - result->type = MYSQLND_RES_NORMAL; + if (!stmt) { + result->type = MYSQLND_RES_NORMAL; } else { - result->type = MYSQLND_RES_PS_UNBUF; + result->type = MYSQLND_RES_PS_UNBUF; } - result->unbuf = mysqlnd_result_unbuffered_init(result, result->field_count, ps); + result->unbuf = mysqlnd_result_unbuffered_init(result, result->field_count, stmt); /* Will be freed in the mysqlnd_internal_free_result_contents() called @@ -782,7 +535,7 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, const zend_b conn->payload_decoder_factory->m.init_row_packet(row_packet); row_packet->result_set_memory_pool = result->unbuf->result_set_memory_pool; row_packet->field_count = result->field_count; - row_packet->binary_protocol = ps; + row_packet->binary_protocol = stmt != NULL; row_packet->fields_metadata = result->meta->fields; result->unbuf->row_packet = row_packet; @@ -793,244 +546,68 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, const zend_b /* }}} */ -/* {{{ mysqlnd_result_buffered::fetch_row_c */ +/* {{{ mysqlnd_result_buffered::fetch_row */ static enum_func_status -MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * const fetched_anything) +MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, zval **row_ptr, const unsigned int flags, zend_bool * fetched_anything) { - enum_func_status ret = FAIL; - MYSQLND_ROW_C * row = (MYSQLND_ROW_C *) param; - const MYSQLND_RES_METADATA * const meta = result->meta; - const unsigned int field_count = meta->field_count; - MYSQLND_CONN_DATA * const conn = result->conn; - DBG_ENTER("mysqlnd_result_buffered::fetch_row_c"); - - if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; - - /* If we haven't read everything */ - if (set->data_cursor && - (set->data_cursor - set->data) < (result->stored_data->row_count * field_count)) - { - zval *current_row = set->data_cursor; - unsigned int i; - - if (Z_ISUNDEF(current_row[0])) { - uint64_t row_num = (set->data_cursor - set->data) / field_count; - enum_func_status rc = set->m.row_decoder(&set->row_buffers[row_num], - current_row, - field_count, - meta->fields, - conn->options->int_and_float_native, - conn->stats); - if (rc != PASS) { - DBG_RETURN(FAIL); - } - } - -/* BEGIN difference between normal normal fetch and _c */ - *row = mnd_emalloc(field_count * sizeof(char *)); - for (i = 0; i < field_count; ++i) { - zval * data = ¤t_row[i]; - - set->lengths[i] = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0; - - if (Z_TYPE_P(data) != IS_NULL) { - convert_to_string(data); - (*row)[i] = Z_STRVAL_P(data); - } else { - (*row)[i] = NULL; - } - } - set->data_cursor += field_count; - MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF); -/* END difference between normal normal fetch and _c */ - - *fetched_anything = *row? TRUE:FALSE; - ret = *row? PASS:FAIL; - } else { - set->data_cursor = NULL; - DBG_INF("EOF reached"); - *fetched_anything = FALSE; - ret = PASS; - } - } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) { - /* - We don't support _C with pdo because it uses the data in a different way - just references it. - We will either leak or give nirvana pointers - */ - *fetched_anything = FALSE; - DBG_RETURN(FAIL); - } - DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything); - DBG_RETURN(ret); -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_zval::fetch_row */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * const fetched_anything) -{ - enum_func_status ret = FAIL; - zval * row = (zval *) param; - const MYSQLND_RES_METADATA * const meta = result->meta; - const unsigned int field_count = meta->field_count; - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; - MYSQLND_CONN_DATA * const conn = result->conn; + MYSQLND_RES_BUFFERED *set = result->stored_data; - DBG_ENTER("mysqlnd_result_buffered_zval::fetch_row"); + DBG_ENTER("mysqlnd_result_buffered::fetch_row"); /* If we haven't read everything */ - if (set->data_cursor && (set->data_cursor - set->data) < (set->row_count * field_count)) { - unsigned int i; - zval *current_row = set->data_cursor; - - if (Z_ISUNDEF(current_row[0])) { - const size_t row_num = (set->data_cursor - set->data) / field_count; - enum_func_status rc = set->m.row_decoder(&set->row_buffers[row_num], - current_row, - field_count, - meta->fields, - conn->options->int_and_float_native, - conn->stats); + if (set->current_row < set->row_count) { + if (row_ptr) { + const MYSQLND_RES_METADATA * const meta = result->meta; + const unsigned int field_count = meta->field_count; + MYSQLND_CONN_DATA * const conn = result->conn; + enum_func_status rc; + zval *current_row = result->row_data; + *row_ptr = result->row_data; + rc = result->stored_data->m.row_decoder(&set->row_buffers[set->current_row], + current_row, + field_count, + meta->fields, + conn->options->int_and_float_native, + conn->stats); if (rc != PASS) { DBG_RETURN(FAIL); } - } - - for (i = 0; i < field_count; ++i) { - zval * data = ¤t_row[i]; - set->lengths[i] = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0; - - if (flags & MYSQLND_FETCH_NUM) { - if (zend_hash_index_add(Z_ARRVAL_P(row), i, data) != NULL) { - Z_TRY_ADDREF_P(data); - } - } - if (flags & MYSQLND_FETCH_ASSOC) { - /* zend_hash_quick_update needs length + trailing zero */ - /* QQ: Error handling ? */ - /* - zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether - the index is a numeric and convert it to it. This however means constant - hashing of the column name, which is not needed as it can be precomputed. - */ - Z_TRY_ADDREF_P(data); - if (meta->fields[i].is_numeric == FALSE) { - zend_hash_update(Z_ARRVAL_P(row), meta->fields[i].sname, data); - } else { - zend_hash_index_update(Z_ARRVAL_P(row), meta->fields[i].num_key, data); + if (set->lengths) { + for (unsigned i = 0; i < field_count; ++i) { + zval *data = ¤t_row[i]; + set->lengths[i] = Z_TYPE_P(data) == IS_STRING ? Z_STRLEN_P(data) : 0; } } } - set->data_cursor += field_count; - MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF); - *fetched_anything = TRUE; - ret = PASS; - } else { - set->data_cursor = NULL; - DBG_INF("EOF reached"); - *fetched_anything = FALSE; - ret = PASS; - } - DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything); - DBG_RETURN(ret); -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_c::fetch_row */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything) -{ - enum_func_status ret = FAIL; - zval * row = (zval *) param; - const MYSQLND_RES_METADATA * const meta = result->meta; - const unsigned int field_count = meta->field_count; - MYSQLND_CONN_DATA * const conn = result->conn; - - MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result->stored_data; - DBG_ENTER("mysqlnd_result_buffered_c::fetch_row"); - - /* If we haven't read everything */ - if (set->current_row < set->row_count) { - enum_func_status rc; - zval * current_row; - unsigned int i; - - current_row = mnd_emalloc(field_count * sizeof(zval)); - rc = result->stored_data->m.row_decoder(&result->stored_data->row_buffers[set->current_row], - current_row, - field_count, - meta->fields, - conn->options->int_and_float_native, - conn->stats); - if (rc != PASS) { - DBG_RETURN(FAIL); - } - - for (i = 0; i < field_count; ++i) { - zval * data = ¤t_row[i]; - - set->lengths[i] = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0; - - if (flags & MYSQLND_FETCH_NUM) { - if (zend_hash_index_add(Z_ARRVAL_P(row), i, data)) { - Z_TRY_ADDREF_P(data); - } - } - if (flags & MYSQLND_FETCH_ASSOC) { - /* zend_hash_quick_update needs length + trailing zero */ - /* QQ: Error handling ? */ - /* - zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether - the index is a numeric and convert it to it. This however means constant - hashing of the column name, which is not needed as it can be precomputed. - */ - Z_TRY_ADDREF_P(data); - if (meta->fields[i].is_numeric == FALSE) { - zend_hash_update(Z_ARRVAL_P(row), meta->fields[i].sname, data); - } else { - zend_hash_index_update(Z_ARRVAL_P(row), meta->fields[i].num_key, data); - } - } - /* - This will usually not destroy anything but decref. - However, if neither NUM nor ASSOC is set we will free memory cleanly and won't leak. - It also simplifies the handling of Z_ADDREF_P because we don't need to check if only - either NUM or ASSOC is set but not both. - */ - zval_ptr_dtor_nogc(data); - } - mnd_efree(current_row); ++set->current_row; - MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF); + MYSQLND_INC_GLOBAL_STATISTIC(set->stmt + ? STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF : STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF); *fetched_anything = TRUE; - ret = PASS; } else { if (set->current_row == set->row_count) { set->current_row = set->row_count + 1; } DBG_INF_FMT("EOF reached. current_row=%llu", (unsigned long long) set->current_row); *fetched_anything = FALSE; - ret = PASS; } DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything); - DBG_RETURN(ret); + DBG_RETURN(PASS); } /* }}} */ /* {{{ mysqlnd_res::fetch_row */ static enum_func_status -MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool *fetched_anything) +MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES *result, zval **row_ptr, const unsigned int flags, zend_bool *fetched_anything) { - const mysqlnd_fetch_row_func f = result->stored_data? result->stored_data->m.fetch_row:(result->unbuf? result->unbuf->m.fetch_row:NULL); + const mysqlnd_fetch_row_func f = + result->stored_data ? result->stored_data->m.fetch_row : + result->unbuf ? result->unbuf->m.fetch_row : NULL; if (f) { - return f(result, param, flags, fetched_anything); + return f(result, row_ptr, flags, fetched_anything); } *fetched_anything = FALSE; return PASS; @@ -1104,13 +681,6 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c /* So row_packet's destructor function won't efree() it */ row_packet.row_buffer.ptr = NULL; - - /* - No need to FREE_ALLOCA as we can reuse the - 'lengths' and 'fields' arrays. For lengths its absolutely safe. - 'fields' is reused because the ownership of the strings has been - transferred above. - */ } /* Overflow ? */ MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, @@ -1173,7 +743,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result, MYSQLND_CONN_DATA * const conn, - const unsigned int flags) + MYSQLND_STMT_DATA *stmt) { enum_func_status ret; MYSQLND_ROW_BUFFER **row_buffers = NULL; @@ -1187,14 +757,10 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result, SET_CONNECTION_STATE(&conn->state, CONN_FETCHING_DATA); - if (flags & MYSQLND_STORE_NO_COPY) { - result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result, result->field_count, flags & MYSQLND_STORE_PS); - row_buffers = &result->stored_data->row_buffers; - } else if (flags & MYSQLND_STORE_COPY) { - result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_c_init(result, result->field_count, flags & MYSQLND_STORE_PS); - row_buffers = &result->stored_data->row_buffers; - } - ret = result->m.store_result_fetch_data(conn, result, result->meta, row_buffers, flags & MYSQLND_STORE_PS); + result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_init(result, result->field_count, stmt); + row_buffers = &result->stored_data->row_buffers; + + ret = result->m.store_result_fetch_data(conn, result, result->meta, row_buffers, stmt != NULL); if (FAIL == ret) { if (result->stored_data) { @@ -1204,30 +770,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result, } DBG_RETURN(NULL); } else { - if (flags & MYSQLND_STORE_NO_COPY) { - const MYSQLND_RES_METADATA * const meta = result->meta; - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; - - if (set->row_count) { - /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ - if (set->row_count * meta->field_count * sizeof(zval *) > SIZE_MAX) { - SET_OOM_ERROR(conn->error_info); - DBG_RETURN(NULL); - } - /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */ - set->data = mnd_emalloc((size_t)(set->row_count * meta->field_count * sizeof(zval))); - if (!set->data) { - SET_OOM_ERROR(conn->error_info); - DBG_RETURN(NULL); - } - memset(set->data, 0, (size_t)(set->row_count * meta->field_count * sizeof(zval))); - } - /* Position at the first row */ - set->data_cursor = set->data; - } else if (flags & MYSQLND_STORE_COPY) { - MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result->stored_data; - set->current_row = 0; - } + result->stored_data->current_row = 0; } /* libmysql's documentation says it should be so for SELECT statements */ @@ -1298,36 +841,17 @@ MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES * const result, const uint64_ /* }}} */ -/* {{{ mysqlnd_result_buffered_zval::data_seek */ +/* {{{ mysqlnd_result_buffered::data_seek */ static enum_func_status -MYSQLND_METHOD(mysqlnd_result_buffered_zval, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row) +MYSQLND_METHOD(mysqlnd_result_buffered, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row) { - MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result; - DBG_ENTER("mysqlnd_result_buffered_zval::data_seek"); + DBG_ENTER("mysqlnd_result_buffered::data_seek"); /* libmysql just moves to the end, it does traversing of a linked list */ - if (row >= set->row_count) { - set->data_cursor = NULL; + if (row >= result->row_count) { + result->current_row = result->row_count; } else { - set->data_cursor = set->data + row * result->field_count; - } - DBG_RETURN(PASS); -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_c::data_seek */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_result_buffered_c, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row) -{ - MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result; - DBG_ENTER("mysqlnd_result_buffered_c::data_seek"); - - /* libmysql just moves to the end, it does traversing of a linked list */ - if (row >= set->row_count) { - set->current_row = set->row_count; - } else { - set->current_row = row; + result->current_row = row; } DBG_RETURN(PASS); } @@ -1443,31 +967,53 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, const unsigned int zval *return_value ZEND_FILE_LINE_DC) { zend_bool fetched_anything; - unsigned int array_size; + zval *row_data; DBG_ENTER("mysqlnd_res::fetch_into"); + if (FAIL == result->m.fetch_row(result, &row_data, flags, &fetched_anything)) { + php_error_docref(NULL, E_WARNING, "Error while reading a row"); + RETVAL_FALSE; + DBG_VOID_RETURN; + } else if (fetched_anything == FALSE) { + RETVAL_NULL(); + DBG_VOID_RETURN; + } - /* - Hint Zend how many elements we will have in the hash. Thus it won't - extend and rehash the hash constantly. - */ - array_size = result->field_count; + const MYSQLND_RES_METADATA * const meta = result->meta; + unsigned int array_size = meta->field_count; if ((flags & (MYSQLND_FETCH_NUM|MYSQLND_FETCH_ASSOC)) == (MYSQLND_FETCH_NUM|MYSQLND_FETCH_ASSOC)) { array_size *= 2; } array_init_size(return_value, array_size); - if (FAIL == result->m.fetch_row(result, (void *)return_value, flags, &fetched_anything)) { - php_error_docref(NULL, E_WARNING, "Error while reading a row"); - zend_array_destroy(Z_ARR_P(return_value)); - RETVAL_FALSE; - } else if (fetched_anything == FALSE) { - zend_array_destroy(Z_ARR_P(return_value)); - RETVAL_NULL(); + + HashTable *row_ht = Z_ARRVAL_P(return_value); + MYSQLND_FIELD *field = meta->fields; + for (unsigned i = 0; i < meta->field_count; i++, field++) { + zval *data = &row_data[i]; + + if (flags & MYSQLND_FETCH_NUM) { + if (zend_hash_index_add(row_ht, i, data) != NULL) { + Z_TRY_ADDREF_P(data); + } + } + if (flags & MYSQLND_FETCH_ASSOC) { + /* zend_hash_quick_update needs length + trailing zero */ + /* QQ: Error handling ? */ + /* + zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether + the index is a numeric and convert it to it. This however means constant + hashing of the column name, which is not needed as it can be precomputed. + */ + Z_TRY_ADDREF_P(data); + if (meta->fields[i].is_numeric == FALSE) { + zend_hash_update(row_ht, meta->fields[i].sname, data); + } else { + zend_hash_index_update(row_ht, meta->fields[i].num_key, data); + } + } + + zval_ptr_dtor_nogc(data); } - /* - return_value is IS_NULL for no more data and an array for data. Thus it's ok - to return here. - */ DBG_VOID_RETURN; } /* }}} */ @@ -1478,16 +1024,26 @@ static MYSQLND_ROW_C MYSQLND_METHOD(mysqlnd_res, fetch_row_c)(MYSQLND_RES * result) { zend_bool fetched_anything; + zval *row_data; MYSQLND_ROW_C ret = NULL; DBG_ENTER("mysqlnd_res::fetch_row_c"); - if (result->stored_data && result->stored_data->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row)) { - MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything); - } else if (result->unbuf && result->unbuf->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)) { - MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything); - } else { - ret = NULL; - php_error_docref(NULL, E_ERROR, "result->m.fetch_row has invalid value. Report to the developers"); + mysqlnd_result_free_prev_data(result); + if (result->m.fetch_row(result, &row_data, 0, &fetched_anything) == PASS && fetched_anything) { + unsigned field_count = result->field_count; + MYSQLND_FIELD *field = result->meta->fields; + + ret = mnd_emalloc(field_count * sizeof(char *)); + for (unsigned i = 0; i < field_count; i++, field++) { + zval *data = &row_data[i]; + if (Z_TYPE_P(data) != IS_NULL) { + convert_to_string(data); + ret[i] = Z_STRVAL_P(data); + } else { + ret[i] = NULL; + } + } + result->free_row_data = 1; } DBG_RETURN(ret); } @@ -1566,17 +1122,16 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_result_unbuffered) NULL, /* row_decoder */ MYSQLND_METHOD(mysqlnd_result_unbuffered, num_rows), MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_lengths), - MYSQLND_METHOD(mysqlnd_result_unbuffered, free_last_data), MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result) MYSQLND_CLASS_METHODS_END; MYSQLND_CLASS_METHODS_START(mysqlnd_result_buffered) - NULL, /* fetch_row */ + MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row), NULL, /* row_decoder */ MYSQLND_METHOD(mysqlnd_result_buffered, num_rows), - NULL, /* fetch_lengths */ - NULL, /* data_seek */ + MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths), + MYSQLND_METHOD(mysqlnd_result_buffered, data_seek), MYSQLND_METHOD(mysqlnd_result_buffered, free_result) MYSQLND_CLASS_METHODS_END; @@ -1599,6 +1154,9 @@ mysqlnd_result_init(const unsigned int field_count) ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); + ret->row_data = pool->get_chunk(pool, field_count * sizeof(zval)); + ret->free_row_data = 0; + ret->memory_pool = pool; ret->field_count = field_count; ret->m = *mysqlnd_result_get_methods(); @@ -1612,7 +1170,7 @@ mysqlnd_result_init(const unsigned int field_count) /* {{{ mysqlnd_result_unbuffered_init */ PHPAPI MYSQLND_RES_UNBUFFERED * -mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_count, const zend_bool ps) +mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt) { const size_t alloc_size = sizeof(MYSQLND_RES_UNBUFFERED) + mysqlnd_plugin_count() * sizeof(void *); MYSQLND_MEMORY_POOL * pool = result->memory_pool; @@ -1623,23 +1181,21 @@ mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_cou ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); - ret->lengths = pool->get_chunk(pool, field_count * sizeof(size_t)); - memset(ret->lengths, 0, field_count * sizeof(size_t)); - - ret->last_row_data = pool->get_chunk(pool, field_count * sizeof(zval)); - memset(ret->last_row_data, 0, field_count * sizeof(zval)); - ret->result_set_memory_pool = pool; - ret->field_count= field_count; - ret->ps = ps; + ret->field_count = field_count; + ret->stmt = stmt; ret->m = *mysqlnd_result_unbuffered_get_methods(); - if (ps) { + if (stmt) { + ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; ret->m.fetch_lengths = NULL; /* makes no sense */ - ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; + ret->lengths = NULL; } else { - ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_zval; + ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol; + + ret->lengths = pool->get_chunk(pool, field_count * sizeof(size_t)); + memset(ret->lengths, 0, field_count * sizeof(size_t)); } DBG_RETURN(ret); @@ -1647,77 +1203,36 @@ mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_cou /* }}} */ -/* {{{ mysqlnd_result_buffered_zval_init */ -PHPAPI MYSQLND_RES_BUFFERED_ZVAL * -mysqlnd_result_buffered_zval_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps) +/* {{{ mysqlnd_result_buffered_init */ +PHPAPI MYSQLND_RES_BUFFERED * +mysqlnd_result_buffered_init(MYSQLND_RES * result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt) { - const size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_ZVAL) + mysqlnd_plugin_count() * sizeof(void *); + const size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED) + mysqlnd_plugin_count() * sizeof(void *); MYSQLND_MEMORY_POOL * pool = result->memory_pool; - MYSQLND_RES_BUFFERED_ZVAL * ret; + MYSQLND_RES_BUFFERED * ret; - DBG_ENTER("mysqlnd_result_buffered_zval_init"); + DBG_ENTER("mysqlnd_result_buffered_init"); ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); mysqlnd_error_info_init(&ret->error_info, /* persistent */ 0); - ret->lengths = pool->get_chunk(pool, field_count * sizeof(size_t)); - memset(ret->lengths, 0, field_count * sizeof(size_t)); - ret->result_set_memory_pool = pool; ret->field_count= field_count; - ret->ps = ps; + ret->stmt = stmt; ret->m = *mysqlnd_result_buffered_get_methods(); - ret->type = MYSQLND_BUFFERED_TYPE_ZVAL; - if (ps) { + if (stmt) { + ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; ret->m.fetch_lengths = NULL; /* makes no sense */ - ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; + ret->lengths = NULL; } else { - ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_zval; - } - ret->m.fetch_row = MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row); - ret->m.fetch_lengths = MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_lengths); - ret->m.data_seek = MYSQLND_METHOD(mysqlnd_result_buffered_zval, data_seek); - DBG_RETURN(ret); -} -/* }}} */ - - -/* {{{ mysqlnd_result_buffered_c_init */ -PHPAPI MYSQLND_RES_BUFFERED_C * -mysqlnd_result_buffered_c_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps) -{ - const size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_C) + mysqlnd_plugin_count() * sizeof(void *); - MYSQLND_MEMORY_POOL * pool = result->memory_pool; - MYSQLND_RES_BUFFERED_C * ret; - - DBG_ENTER("mysqlnd_result_buffered_c_init"); - - ret = pool->get_chunk(pool, alloc_size); - memset(ret, 0, alloc_size); + ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol; - mysqlnd_error_info_init(&ret->error_info, /* persistent */ 0); - - ret->lengths = pool->get_chunk(pool, field_count * sizeof(size_t)); - memset(ret->lengths, 0, field_count * sizeof(size_t)); - - ret->result_set_memory_pool = pool; - ret->field_count= field_count; - ret->ps = ps; - ret->m = *mysqlnd_result_buffered_get_methods(); - ret->type = MYSQLND_BUFFERED_TYPE_C; - - if (ps) { - ret->m.fetch_lengths = NULL; /* makes no sense */ - ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; - } else { - ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_c; + ret->lengths = pool->get_chunk(pool, field_count * sizeof(size_t)); + memset(ret->lengths, 0, field_count * sizeof(size_t)); } - ret->m.fetch_row = MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_row); - ret->m.fetch_lengths = MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_lengths); - ret->m.data_seek = MYSQLND_METHOD(mysqlnd_result_buffered_c, data_seek); DBG_RETURN(ret); } diff --git a/ext/mysqlnd/mysqlnd_result.h b/ext/mysqlnd/mysqlnd_result.h index 14f894ccba407..9dde8a5fade42 100644 --- a/ext/mysqlnd/mysqlnd_result.h +++ b/ext/mysqlnd/mysqlnd_result.h @@ -19,9 +19,8 @@ #define MYSQLND_RESULT_H PHPAPI MYSQLND_RES * mysqlnd_result_init(const unsigned int field_count); -PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps); -PHPAPI MYSQLND_RES_BUFFERED_ZVAL * mysqlnd_result_buffered_zval_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps); -PHPAPI MYSQLND_RES_BUFFERED_C * mysqlnd_result_buffered_c_init(MYSQLND_RES * result, const unsigned int field_count, const zend_bool ps); +PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(MYSQLND_RES * result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt); +PHPAPI MYSQLND_RES_BUFFERED * mysqlnd_result_buffered_init(MYSQLND_RES * result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt); enum_func_status mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * stmt); diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 5f4c03d7c8dd7..47c8e491ec08d 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -279,9 +279,7 @@ typedef struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND; typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND; typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA; -typedef struct st_mysqlnd_buffered_result_parent MYSQLND_RES_BUFFERED; -typedef struct st_mysqlnd_buffered_result_zval MYSQLND_RES_BUFFERED_ZVAL; -typedef struct st_mysqlnd_buffered_result_c MYSQLND_RES_BUFFERED_C; +typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED; typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED; typedef struct st_mysqlnd_debug MYSQLND_DEBUG; @@ -289,7 +287,7 @@ typedef struct st_mysqlnd_debug MYSQLND_DEBUG; typedef MYSQLND_RES* (*mysqlnd_stmt_use_or_store_func)(MYSQLND_STMT * const); typedef enum_func_status (*mysqlnd_fetch_row_func)(MYSQLND_RES *result, - void * param, + zval **row, const unsigned int flags, zend_bool * fetched_anything ); @@ -441,8 +439,8 @@ typedef enum_func_status (*func_mysqlnd_conn_data__set_charset)(MYSQLND_CONN_DAT typedef enum_func_status (*func_mysqlnd_conn_data__query)(MYSQLND_CONN_DATA * conn, const char * const query, const size_t query_len); typedef enum_func_status (*func_mysqlnd_conn_data__send_query)(MYSQLND_CONN_DATA * conn, const char * const query, const size_t query_len, enum_mysqlnd_send_query_type type, zval *read_cb, zval *err_cb); typedef enum_func_status (*func_mysqlnd_conn_data__reap_query)(MYSQLND_CONN_DATA * conn, enum_mysqlnd_reap_result_type type); -typedef MYSQLND_RES * (*func_mysqlnd_conn_data__use_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags); -typedef MYSQLND_RES * (*func_mysqlnd_conn_data__store_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags); +typedef MYSQLND_RES * (*func_mysqlnd_conn_data__use_result)(MYSQLND_CONN_DATA * const conn); +typedef MYSQLND_RES * (*func_mysqlnd_conn_data__store_result)(MYSQLND_CONN_DATA * const conn); typedef enum_func_status (*func_mysqlnd_conn_data__next_result)(MYSQLND_CONN_DATA * const conn); typedef zend_bool (*func_mysqlnd_conn_data__more_results)(const MYSQLND_CONN_DATA * const conn); @@ -638,8 +636,8 @@ typedef enum_func_status (*func_mysqlnd_res__row_decoder)(MYSQLND_ROW_BUFFER * r const zend_bool as_int_or_float, MYSQLND_STATS * const stats); -typedef MYSQLND_RES * (*func_mysqlnd_res__use_result)(MYSQLND_RES * const result, const zend_bool ps_protocol); -typedef MYSQLND_RES * (*func_mysqlnd_res__store_result)(MYSQLND_RES * result, MYSQLND_CONN_DATA * const conn, const unsigned int flags); +typedef MYSQLND_RES * (*func_mysqlnd_res__use_result)(MYSQLND_RES * const result, MYSQLND_STMT_DATA *stmt); +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); @@ -661,7 +659,6 @@ typedef void (*func_mysqlnd_res__free_result_buffers)(MYSQLND_RES * result); typedef enum_func_status (*func_mysqlnd_res__free_result)(MYSQLND_RES * result, const zend_bool implicit); typedef void (*func_mysqlnd_res__free_result_contents)(MYSQLND_RES *result); typedef void (*func_mysqlnd_res__free_buffered_data)(MYSQLND_RES *result); -typedef void (*func_mysqlnd_res__unbuffered_free_last_data)(MYSQLND_RES *result); typedef MYSQLND_RES_METADATA * (*func_mysqlnd_res__result_meta_init)(MYSQLND_RES *result, unsigned int field_count); @@ -703,7 +700,6 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_res) typedef uint64_t (*func_mysqlnd_result_unbuffered__num_rows)(const MYSQLND_RES_UNBUFFERED * const result); typedef const size_t * (*func_mysqlnd_result_unbuffered__fetch_lengths)(const MYSQLND_RES_UNBUFFERED * const result); -typedef void (*func_mysqlnd_result_unbuffered__free_last_data)(MYSQLND_RES_UNBUFFERED * result, MYSQLND_STATS * const global_stats); typedef void (*func_mysqlnd_result_unbuffered__free_result)(MYSQLND_RES_UNBUFFERED * const result, MYSQLND_STATS * const global_stats); MYSQLND_CLASS_METHODS_TYPE(mysqlnd_result_unbuffered) @@ -712,7 +708,6 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_result_unbuffered) func_mysqlnd_res__row_decoder row_decoder; func_mysqlnd_result_unbuffered__num_rows num_rows; func_mysqlnd_result_unbuffered__fetch_lengths fetch_lengths; - func_mysqlnd_result_unbuffered__free_last_data free_last_data; func_mysqlnd_result_unbuffered__free_result free_result; }; @@ -1178,48 +1173,30 @@ struct st_mysqlnd_result_metadata }; -#define def_mysqlnd_buffered_result_parent \ - MYSQLND_ROW_BUFFER *row_buffers; \ - uint64_t row_count; \ - \ - /* Column lengths of current row - both buffered and unbuffered. For buffered results it duplicates the data found in **data */ \ - size_t *lengths; \ - \ - MYSQLND_MEMORY_POOL *result_set_memory_pool; \ - \ - unsigned int references; \ - \ - MYSQLND_ERROR_INFO error_info; \ - \ - unsigned int field_count; \ - zend_bool ps; \ - MYSQLND_CLASS_METHODS_TYPE(mysqlnd_result_buffered) m; \ - enum mysqlnd_buffered_type type; \ - void * unused1; \ - void * unused2; \ - void * unused3 - - -struct st_mysqlnd_buffered_result_parent +struct st_mysqlnd_buffered_result { - def_mysqlnd_buffered_result_parent; -}; + MYSQLND_CLASS_METHODS_TYPE(mysqlnd_result_buffered) m; + MYSQLND_ROW_BUFFER *row_buffers; + uint64_t row_count; -struct st_mysqlnd_buffered_result_zval -{ - def_mysqlnd_buffered_result_parent; + /* Column lengths of current row - both buffered and unbuffered. For buffered results it duplicates the data found in **data */ + size_t *lengths; - zval *data; - zval *data_cursor; -}; + MYSQLND_MEMORY_POOL *result_set_memory_pool; + unsigned int references; -struct st_mysqlnd_buffered_result_c -{ - def_mysqlnd_buffered_result_parent; + MYSQLND_ERROR_INFO error_info; + + unsigned int field_count; + MYSQLND_STMT_DATA *stmt; uint64_t current_row; + + void * unused1; + void * unused2; + void * unused3; }; @@ -1229,7 +1206,6 @@ struct st_mysqlnd_unbuffered_result uint64_t row_count; /* For unbuffered (both normal and PS) */ - zval *last_row_data; MYSQLND_ROW_BUFFER last_row_buffer; /* @@ -1246,7 +1222,7 @@ struct st_mysqlnd_unbuffered_result zend_bool eof_reached; - zend_bool ps; + MYSQLND_STMT_DATA *stmt; }; @@ -1256,6 +1232,9 @@ struct st_mysqlnd_res enum_mysqlnd_res_type type; unsigned int field_count; + zval *row_data; + bool free_row_data; + /* For metadata functions */ MYSQLND_RES_METADATA *meta; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index a0ba748a6cbee..0d601e5b98263 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -1369,7 +1369,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc, */ /* - We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol_aux + We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol needs to be able to append a terminating \0 for atoi/atof. */ prealloc_more_bytes = 1; @@ -1525,7 +1525,7 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi /* {{{ php_mysqlnd_rowp_read_text_protocol */ enum_func_status -php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, +php_mysqlnd_rowp_read_text_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, unsigned int field_count, const MYSQLND_FIELD * fields_metadata, zend_bool as_int_or_float, MYSQLND_STATS * stats) { @@ -1535,7 +1535,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * const size_t data_size = row_buffer->size; const zend_uchar * const packet_end = (zend_uchar*) p + data_size; - DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux"); + DBG_ENTER("php_mysqlnd_rowp_read_text_protocol"); if (!fields) { DBG_RETURN(FAIL); @@ -1667,34 +1667,6 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * /* }}} */ -/* {{{ php_mysqlnd_rowp_read_text_protocol_zval */ -enum_func_status -php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, - const unsigned int field_count, const MYSQLND_FIELD * fields_metadata, - const zend_bool as_int_or_float, MYSQLND_STATS * stats) -{ - enum_func_status ret; - DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval"); - ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats); - DBG_RETURN(ret); -} -/* }}} */ - - -/* {{{ php_mysqlnd_rowp_read_text_protocol_c */ -enum_func_status -php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, - const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata, - const zend_bool as_int_or_float, MYSQLND_STATS * const stats) -{ - enum_func_status ret; - DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c"); - ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats); - DBG_RETURN(ret); -} -/* }}} */ - - /* {{{ php_mysqlnd_rowp_read */ static enum_func_status php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet) diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index 28d521644e141..7cbfe0afd6999 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -308,11 +308,7 @@ enum_func_status php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_ zend_bool as_int_or_float, MYSQLND_STATS * stats); -enum_func_status php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, - unsigned int field_count, const MYSQLND_FIELD * fields_metadata, - zend_bool as_int_or_float, MYSQLND_STATS * stats); - -enum_func_status php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, +enum_func_status php_mysqlnd_rowp_read_text_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fields, unsigned int field_count, const MYSQLND_FIELD * fields_metadata, zend_bool as_int_or_float, MYSQLND_STATS * stats); diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 15be407414c23..0152abfdf9db3 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -153,7 +153,6 @@ static PHP_GINIT_FUNCTION(mysqlnd) mysqlnd_globals->debug_calloc_fail_threshold = -1; mysqlnd_globals->debug_realloc_fail_threshold = -1; mysqlnd_globals->sha256_server_public_key = NULL; - mysqlnd_globals->fetch_data_copy = FALSE; } /* }}} */ @@ -186,7 +185,6 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("mysqlnd.log_mask", "0", PHP_INI_ALL, OnUpdateLong, log_mask, zend_mysqlnd_globals, mysqlnd_globals) STD_PHP_INI_ENTRY("mysqlnd.mempool_default_size","16000", PHP_INI_ALL, OnUpdateLong, mempool_default_size, zend_mysqlnd_globals, mysqlnd_globals) STD_PHP_INI_ENTRY("mysqlnd.sha256_server_public_key",NULL, PHP_INI_PERDIR, OnUpdateString, sha256_server_public_key, zend_mysqlnd_globals, mysqlnd_globals) - STD_PHP_INI_BOOLEAN("mysqlnd.fetch_data_copy", "0", PHP_INI_ALL, OnUpdateBool, fetch_data_copy, zend_mysqlnd_globals, mysqlnd_globals) #if PHP_DEBUG STD_PHP_INI_ENTRY("mysqlnd.debug_malloc_fail_threshold","-1", PHP_INI_SYSTEM, OnUpdateLong, debug_malloc_fail_threshold, zend_mysqlnd_globals, mysqlnd_globals)