summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UPGRADING5
-rw-r--r--ext/mysqli/mysqli_api.c6
-rw-r--r--ext/mysqli/mysqli_nonapi.c11
-rw-r--r--ext/mysqli/mysqli_warning.c2
-rw-r--r--ext/mysqlnd/mysqlnd.h6
-rw-r--r--ext/mysqlnd/mysqlnd_connection.c29
-rw-r--r--ext/mysqlnd/mysqlnd_enum_n_def.h12
-rw-r--r--ext/mysqlnd/mysqlnd_ext_plugin.c21
-rw-r--r--ext/mysqlnd/mysqlnd_ext_plugin.h6
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c287
-rw-r--r--ext/mysqlnd/mysqlnd_ps.h4
-rw-r--r--ext/mysqlnd/mysqlnd_result.c821
-rw-r--r--ext/mysqlnd/mysqlnd_result.h5
-rw-r--r--ext/mysqlnd/mysqlnd_structs.h73
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c34
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.h6
-rw-r--r--ext/mysqlnd/php_mysqlnd.c2
17 files changed, 257 insertions, 1073 deletions
diff --git a/UPGRADING b/UPGRADING
index 7f43588048..7f530497e7 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 405618896a..0fc7017960 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 364638c44a..6ea09b1fc2 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 6dd7090911..30af6cb960 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 b4d3d1f8c3..582d8f152b 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 21eb7e703b..4d25488ee6 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 @@ end:
/* {{{ 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 191b8388b3..6d6cefbb46 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 58a4ee767e..cf28b81ea5 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 713eb1f44f..027fda976a 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 ccafa26675..7811f51832 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, &current_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 0d4f7f8068..9e10fbab77 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 05a04296e6..620f205998 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 = &current_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 = &current_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 = &current_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 = &current_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 @@ end:
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 14f894ccba..9dde8a5fad 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 5f4c03d7c8..47c8e491ec 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 a0ba748a6c..0d601e5b98 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 28d521644e..7cbfe0afd6 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 15be407414..0152abfdf9 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)